Class declaration:
class unaryOperators
{
public:
int i;
unaryOperators (int tempI = 0)
{
i = tempI;
}
unaryOperators operator++ (int);
unaryOperators operator++ ();
};
Does this global definition correspond to postfix or prefix version of the overloaded operator++? Why?
unaryOperators operator++ (unaryOperators &one)
{
return one;
}
unaryOperators& operator++ (unaryOperators &one)
^^
is the non-member prefix unary increment operator.
The non-member postfix unary increment operator takes an additional int as an policy enforcing parameter.
unaryOperators operator++ (unaryOperators &one, int)
Reference:
C++03 Standard 13.5.7 Increment and decrement [over.inc]
The user-defined function called operator++ implements the prefix and postfix ++ operator. If this function is a member function with no parameters, or a non-member function with one parameter of class or enumeration type, it defines the prefix increment operator ++ for objects of that type. If the function is a member function with one parameter (which shall be of type int) or a non-member function with two parameters (the second of which shall be of type int), it defines the postfix increment operator ++ for objects of that type. When the postfix increment is called as a result of using the ++ operator, the int argument will have value zero.125)
[Example:
class X {
public:
X& operator++(); // prefix ++a
X operator++(int); // postfix a++
};
class Y { };
Y& operator++(Y&); // prefix ++b
Y operator++(Y&, int); // postfix b++
void f(X a, Y b) {
++a; // a.operator++();
a++; // a.operator++(0);
++b; // operator++(b);
b++; // operator++(b, 0);
a.operator++(); // explicit call: like ++a;
a.operator++(0); // explicit call: like a++;
operator++(b); //explicit call: like ++b;
operator++(b, 0); // explicit call: like b++;
}
—end example]
I think this will help you.
Every operator (that can be overloaded as a free function) takes one more argument when overloaded as a free function. The first argument corresponds to *this when overloaded as a member function.
bool AsMember::operator!() const;
bool operator!(const AsFreeFunction&);
bool AsMember::operator==(const AsMember& rhv) const;
bool operator==(const AsFreeFunction& lhv, const AsFreeFunction& rhv);
etc.
Increment operator is no exception to this.
Global overloaded operator++ functions expect the explicit specification of all the arguments, so if the overloaded operator ++ is postfix, we are supposed to add one default int argument (to distinguish postfix version from prefix) in addition to the prerequisite one (which determines the type on which the function needs to be applied).
unaryOperators operator++ (unaryOperators &one, int dummy)
{
return one;
}
In the case of prefix global overloaded operator++ functions, the only argument we need to specify is the prerequisite one (which determines the type on which the function needs to be applied).
unaryOperators operator++ (unaryOperators &one)
{
return one;
}
The free function is prefix as it lacks an int parameter.
Helpful guide for operator signatures.
The canonical version of preincrement is:
T &operator++(T &)
That is, return the operand by reference. Postincrement takes an unused int, so the global operator++ you defined is the preincrement operator.
Related
When the free operator function and the member operator function are both defined, which one is used for comparison?
#include <iostream>
class A;
class B;
bool operator==(const A &a, const B &b){ return true; };
class A
{
public:
bool operator==( const B &rhs ){ return false; };
};
class B
{
};
int main( int argc, char **argv )
{
A a;
B b;
if( a == b )
{
std::cout << "a==b" << std::endl;
}
};
I ran the code a couple times and it seems that the member operator wins out. Is this always the case?
I ran the code a couple times and it seems that the member operator wins out.
Yes, the member wins in your example. But not for the reason you think.
Member functions have an implicit object parameter (what this points to), and the type of the object parameter is determined by the cv-qualifiers at the end of the member function. In this case, your member operator has no cv-qualifiers, so the type of the implicit object is simply A.
Basically, we have two candidates:
bool operator==(A const&, B const&); // your non-member operator
bool operator==(A&, B const&); // your member operator
The member operator is a better match because the first parameter is a better match - we don't have to take a more const-qualified reference to a.
If you had made your operator const (as you generally should), then we'd have these two candidates:
bool operator==(A const&, B const&); // your non-member operator
bool operator==(A const&, B const&); // better member operator
Which are identical, there is no reason to prefer one to the other, and we'd get an ambiguity. There is no rule to prefer a member to a non-member function (or vice versa).
You're declaring the 1st parameter type as const & in the non-member operator. Then given a == b, for the non-member operator to be called a needs to be converted to const. On the other hand the member operator is declared as non-const, then its operand is a non-const A then it's an exact match and wins in overload resolution.
If you change the 1st parameter type of the non-member operator to A& you'll get an ambiguity error. LIVE
Or qualify the member operator as const you'll get the ambiguity error too. LIVE
Is it possible to write lambda expression for overloading operators?
For example, I have the following structure:
struct X{
int value;
//(I can't modify this structure)
};
X needs == operator
int main()
{
X a = { 123 };
X b = { 123 };
//[define equality operator for X inside main function]
//if(a == b) {}
return 0;
}
== operator can be defined as bool operator==(const X& lhs, const X& rhs){...}, but this requires adding a separate function, and my comparison is valid only within a specific function.
auto compare = [](const X& lhs, const X& rhs){...} will solve the problem. I was wondering if I can write this lambda as an operator.
Is it possible to write lambda expression for overloading operators?
No.
Operator overload functions must be functions or function templates. They can be member functions, member function templates, non-member functions, or non-member function templates. However, they cannot be lambda expressions.
From the C++11 Standard/13.5 Overloaded operators, para 6:
An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.
I have this class definition:
class foo{
public:
foo();
foo(const int& var);
foo(const foo& var);
~foo();
const foo operator +(const foo& secondOp) const;
private:
int a;
//plus other values, pointers, e.t.c.
};
Also I have made this implementation for '+' operator overloading:
const foo foo::operator +(const foo& secondOp) const{
//I want here to check if i have one operand or two...
if ((FIRST_OPERAND.a!=0) && (secondOp.a==0)){
cout << "ERROR, second operand is zero";
return FIRST_OPERAND;
}
else if ((FIRST_OPERAND.a==0) && (secondOp.a!=0)){
cout << "ERROR, first operand is zero";
return secondOp;
}
}
When i write in main():
foo a(2);
foo b;
foo c;
//I want here to print the ERROR and
//return only the values of a
c = a + b;
Ηow can i return the value of the first operand if the second operand is zero and vice versa?
You're almost there. Since it's a member function, the first operand is *this, so replace FIRST_OPERAND.a with this->a or just a.
However, it might be better to make it a non-member function to allow conversions on both operands (i.e. to be able to write a + 2 or 2 + a). It will need to be a friend in order to access the private member(s).
friend foo operator +(const foo& firstOp, const foo& secondOp);
Also, it's best not to return a const value as that prevents moving from the return value.
It is the compiler that checks the syntaxical correctness of the program. It is unable to distinguish whether you indeed wanted to write
c = a;
that is to do the assignment or you wanted to write
c = a + b;
The both statements are correct.
It is a so-called logical error. The compiler is unable to see what we thoght.
For your line c = a; The assignment operator is implemented by the compiler (just shallow copying the object memory).
That is the reason your code compiles "without the second operand".
If you wish to disallow using the assignment operator - hide it. E.g. by implementing with the private access modifier.
You have to define this function as a friend function
friend Int operator + (int first, Int &second);
this function can perform obj + 2 or 2 + obj.
Int operator + (int first, Int& second){
second.a += first;
return second;
}
I have overloaded the prefix version of operator ++. How can I overload the postfix version if the overloaded function is NOT a member of my class*?
#include <iostream>
using namespace std;
class Number{
int number;
public:
Number(int inNr):number(inNr){}
friend void operator++(Number& fst);
};
void operator++(Number& fst){
fst.number=fst.number+1;
}
int main(){
Number nr1(1);
++nr1;
//nr1++; error: no 'operator++(int)' declared for postfix '++'
}
*I understand if it is a member of the class, I can use the dummy int parameter to distinguish them.
Non-member overloads also use a dummy int parameter to distinguish them:
friend void operator++(Number&); // prefix
friend void operator++(Number&, int); // postfix
Note that some people might expect these to emulate the behaviour of the built-in operator by returning, respectively, the new and old values:
Number& operator++(Number& fst) {
fst.number=fst.number+1;
return fst; // reference to new value
}
Number operator++(Number& fst, int) {
Number old = fst;
++fst;
return old; // copy of old value
}
I believe (I can't test this out at the moment) you use the dummy int as a second parameter to the operator overload, i.e.
void operator++(Number& fst, int /*dummy*/){
fst.number=fst.number+1;
}
#include <iostream>
#include <fstream>
using namespace std;
class binaryOperators
{
public:
int i;
binaryOperators (int tempI = 0)
{
i = tempI;
}
binaryOperators operator<< (const binaryOperators &right);
};
binaryOperators operator<< (const binaryOperators &left, const binaryOperators &right)
{
cout << "\nOne";
return left;
}
binaryOperators binaryOperators :: operator<< (const binaryOperators &right)
{
cout << "\nTwo";
return *this;
}
int main ()
{
binaryOperators obj;
// Compiler's behavior: This statement calls the overloaded operator << declared inside the class.
obj << 5 << 3 << 2;
// Compiler's behavior: This statement calls the overloaded operator << declared outside the class.
2 << obj;
return 0;
}
I have written the comments inside the main() function.
What's the reason for this sort of compiler's behavior?
Is this behavior compiler dependent?
GCC on Linux
The behavior you're seeing is caused by const-correctness. The operator<< defined within the class is non-const, so it can only operate on a non-const object or reference, such as obj. The non-member version outside the class has two constant operands.
If you wrote the member version as a non-member, it would look like this:
binaryOperators operator<< (binaryOperators &left, const binaryOperators &right)
{
cout << "\nTwo";
return left;
}
When overload-matching, the compiler chooses the best fit. In the first case, the left operand is non-const, so it chooses the member operator. In the second case, the left operand is an rvalue (temporary binaryOperators), which is referenced as const, so the non-member operator is chosen.
This behaviour makes complete sense:
When a member function exists and matches, then it is a good idea to use it in preference to a free function, otherwise code outside the class could inadvertently break up the class encapsulation (for example, if another member function were to use the operator<<).
Automatic conversion works by creating a list of candidate functions, then attempting to find conversions for any parameters that require it. In order to find the member function, a conversion would have to happen before building the candidate list, so only the free function is found.