In some cases, we need a variable only temporarily. For example, consider the following situation:
int Add(int nX, int nY)
{
int nSum = nX + nY;
return nSum;
}
int main()
{
using namespace std;
cout << Add(5, 3);
return 0;
}
In the Add() function, note that the nSum variable is really only used as a temporary placeholder variable. It doesn’t contribute much — rather, it’s only function is to transfer the result of the expression to the return value.
There is actually an easier way to write the Add() function using an anonymous variable. An anonymous variable is a variable that is given no name. Anonymous variables in C++ have “expression scope”, meaning they are destroyed at the end of the expression in which they are created. Consequently, they must be used immediately!
Here is the Add() function rewritten using an anonymous variable:
int Add(int nX, int nY)
{
return nX + nY;
}
When the expression nX + nY is evaluated, the result is placed in an anonymous, unnamed variable. A copy of the anonymous variable is returned to the caller by value.
This not only works with return values, but also with function parameters. For example, instead of this:
void PrintValue(int nValue)
{
using namespace std;
cout << nValue;
}
int main()
{
int nSum = 5 + 3;
PrintValue(nSum);
return 0;
}
We can write this:
int main()
{
PrintValue(5 + 3);
return 0;
}
In this case, the expression 5 + 3 is evaluated to produce the result 8, which is placed in an anonymous variable. A copy of this anonymous variable is then passed to the PrintValue() function, which prints the value 8.
Note how much cleaner this keeps our code — we don’t have to litter the code with temporary variables that are only used once.
Anonymous class objects
Although our prior examples have been with built-in data types, it is possible to construct anonymous objects of our own class types as well. This is done by creating objects like normal, but omitting the variable name.
Cents cCents(5); // normal variable Cents(7); // anonymous variable
In the above code, Cents(7) will create an anonymous Cents object, initialize it with the value 7, and then destroy it. In this context, that isn’t going to do us much good. So let’s take a look at an example where it can be put to good use:
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents) { m_nCents = nCents; }
int GetCents() { return m_nCents; }
};
Cents Add(Cents &c1, Cents &c2)
{
Cents cTemp(c1.GetCents() + c2.GetCents());
return cTemp;
}
int main()
{
Cents cCents1(6);
Cents cCents2(8);
Cents cCentsSum = Add(cCents1, cCents2);
std::cout << "I have " << cCentsSum.GetCents() << " cents." << std::endl;
return 0;
}
Note that this example is very similar to the prior one using integers. In this case, our Add() function is constructing a short-lived cTemp variable that only serves as a placeholder. We are also using a cCentsSum variable in main().
We can simplify this program by using anonymous variables:
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents) { m_nCents = nCents; }
int GetCents() { return m_nCents; }
};
Cents Add(Cents &c1, Cents &c2)
{
return Cents(c1.GetCents() + c2.GetCents());
}
int main()
{
Cents cCents1(6);
Cents cCents2(8);
std::cout << "I have " << Add(cCents1, cCents2).GetCents() << " cents." << std::endl;
return 0;
}
This version of Add() functions identically to the one above, except it uses an anonymous Cents value instead of a named variable. Also note that in main(), we no longer use a named cCentsSum variable as temporary storage. Instead, we use the return value of Add() anonymously!
As a result, our program is shorter, cleaner, and generally easier to follow (once you understand the concept).
In C++, anonymous variables are primarily used either to pass or return values without having to create lots of temporary variables to do so. However, it is worth noting that anonymous objects can only be passed or returned by value! If a variable is passed or returned by reference or address, a named variable must be used instead. It is also worth noting that because anonymous variables have expression scope, if you need to reference a value in multiple expressions, you will have to use a named variable.
9.1 — Introduction to operator overloading
|
Index
|
8.13 — Friend functions and classes
|
9.1 — Introduction to operator overloading
Index
8.13 — Friend functions and classes
In the last coding example, how were we able to call the Add function directly from the main() function? Why didn’t we use Cents.Add instead? Also, how can we define an anonymous variable like Cents(7) for instance? How does the compiler act in terms of returning pointers or references to be able to define an anonymous variable?
In the last example, note that Add() is written as a non-member function. Consequently, it can be called directly. We didn’t use Cents.Add() because we didn’t write an Add() member function for this version of the Cents class. We certainly could have, but it was easier to show anonymous variables in action this way.
Cents(7) _is_ an anonymous variable because it was never given a variable name. Perhaps I am misunderstanding this part of your question?
Anonymous variables are always dealt with by value. It is not possible to create a pointer or reference to an anonymous variable, nor is it possible to use an anonymous variable where a pointer or reference parameter or return value is expected.
“It is not possible to create a pointer or reference to an anonymous variable.”
I beg to differ:
int main() { int const & a = (2 + 2); std::cout << a; }What is a “non-member function” anyway? The line:
seems pretty confusing to me, as I thought we would have to declare at least the Add() function’s prototype somewhere in the class definition and then use Cents::Add() for the actual implementation?
Pls excuse me if I missed it and non-member functions had already been covered.
A non-member function is a function that does not belong to a class. They are the functions that you first learned about before you even knew what a class was!
For example:
int Add(int nX, int nY) { return nX + nY; }This is a simple non-member function. It does not belong to a class. In the same way, the Add() function above is a non-member function, except it adds Cents instead of ints.
We could certainly have written Add() as a normal member function of Cents (in which case, it would have been Cents::Add()), but it would have been somewhat awkward to do so, since we’d have to call it like this:
Cents cResult = cCents1.Add(cCents2);
Probably the best solution would have been to make Add() a static member function of Cents. In that case, we could have called it like this:
Cents cResult = Cents::Add(cCents1, cCents2);
I guessed I was just mixing something up. So ‘Cents’ was just a simple return value..
Thx for the quick answer and this outstanding tutorial.
Yes, Cents is a return value.
What’s really throwin me is line #22. Where I understand the:
Add(cCents1, cCents2) part but the .GetCents is confusing.
Which .GetCents is being called? cCents1.GetCents() or
cCents2.GetCents()?
I’m thinking like: Add(cCents1.GetCents(), cCents2.GetCents())
Thanks for your help.
Dano
The first thing that happens is that Add(cCents1, cCents2) is called. Add() creates a new Cents object, which it returns to the caller. Then, GetCents() is called on the return value of the Add() function.
[...] 8.14 — Anonymous variables and objects [...]
i can’t understand why c1 and c2 are passed by reference ??!!
If they weren’t, you couldn’t access them later on in the function:
Cents Add(Cents &c1, Cents &c2) { //here return Cents(c1.GetCents() + c2.GetCents()); }nice!!!
In fact, I think you could write the main function without any named variables at all:
int main() { std::cout << "I have " << Add(Cents(6), Cents(8)).GetCents() << " cents." << std::endl; return 0; }Hold your horses. You can write a function of type class? And how this works? :
Cents cCentsSum = Add(cCents1, cCents2);
Shouldn’t it be like:
Cents cCentsSum(Add(cCents1, cCents2));
I really want to know how things like this work.
declares an object cCentsSum of type Cents and then initialises it, all on one line. It could have been split into two commands:-
The Add function returns an object of type Cents so this initialisation is valid. Note that the Add function is not a member of the class cents, it’s defined outside the class, so is a “normal” function. It’s ok to use functions or expressions as initialisation values, we are not restricted to literals.
I totally disagree with the fact that anonymous types cannot be passed by reference to a function.
#include <iostream> #include <string> using namespace std; void print(const string & mess) { cout << mess << endl; } int main() { print( "Hello world" ); // or print( string( "Hello world" ) + "?" ); return 0; }Great guide. I thought I would add some advice for those new to programming:
If you’re using the same expression in anonymous values repeatedly, it should probably be a named variable instead. For example, if you’re passing strlen(szName) into the value of 3 different functions, capture it in a named variable and use that three times, instead.
This way, strlen(szName) doesn’t have to be calculated three times. It also makes the code more compact and thus more readable.
got a doubt here. Consider the same class.
class Cents { private: int m_nCents; public: Cents(int nCents) { m_nCents = nCents; } int GetCents(Cents obj) { obj.m_nCents =10;} }; int main() { Cents c1,c2; c1.GetCents(c2); } If you consider the function GetCents, am accessing the private variable of technically a different object namely obj. Why am I allowed to do this? Does not this override the quality that the private member of a class cannot be accessed by outside code? Regards, SmithaHi Alex,
Your explanations are precise and that too in simple language. thanks for posting such an useful site.
One quick query. What about Static objects ? I have heard that there are something called as Static objects. I couldn’t find anywhere in the site. Is that being missed in the post or is there really anything called as Static Objects ?
Please can you confirm this ?