While reading this article it seems that the operator + is unary. How is that.
From my understanding a unary operator is an operator that does not depend on another variable for its operation like ++a or a-- . How is the variable '+' unary. I thought it was binary ? I would appreciate it if some one could clear this up.
+ is both a unary and binary operator. The unary + form (+a) forces the operand to be evaluated as a number or a pointer, while the binary form + form (a + b) is addition.
Unary + is generally the opposite of unary -; applying it to any numeric value will not change it. (+1 == 1) However, it does have some uses, including forcing an array to decay into a pointer:
template <typename T> void foo(const T &) { }
void test() {
int a[10];
foo(a); // Calls foo<int[10]>()
foo(+a); // Calls foo<int*>()
}
(Demo)
It's the same deal with the - and * operators. You have -a (negation) and a - b (subtraction); *a (pointer dereference) and a * b (multiplication).
You overload both versions differently. For overloading via member functions:
public:
T operator+() const; // Unary
T operator+(const U &) const; // Binary
As with any other operator overload, both forms can return a value different from their enclosing type; for example you might have a string class whose operator+() returns a numeric type. This would be in line with the convention of unary + evaluating its operand as a number.
You can overload these operators as free functions, too:
T operator+(const U &); // Unary, called on type U and returns T.
T operator+(const U &, const V &); // Binary, called on types U and V and returns T.
Unary + as in +a is defined to complement unary - (-a). It is the "default" so actually not often if ever used. However it can be used with variables refering to classes, where it can be overloaded to have a class-specific meaning. So it is not quite entirely useless.
Related
Suppose we have the following class:
class Rational { // Represents rational number. n=1/2=d for example.
public:
int n = 0;
int d = 1;
};
Rational x = Rational();
x.n = 1;
x.d = 2;
Is it possible to do overloading such that 3 * x would give 3/2 instead of an error?
My teacher said that overloading happens only between objects of the same type, but why can we do overloading between cout which is of type ostream and an object of type Rational and not of the type int and Rational?
You may write for example
Rational operator *( const Rational &r, int x )
{
return { r.n * x, r.d };
}
Rational operator *( int x, const Rational &r )
{
return { r.n * x, r.d };
}
You may overload operators for user defined types. For a binary operator at least one of operands must be of a user defined type.
From the C++ 20 Standard (12.4.2.3 Operators in expressions)
2 If either operand has a type that is a class or an enumeration, a
user-defined operator function can be declared that implements this
operator or a user-defined conversion can be necessary to convert the
operand to a type that is appropriate for a built-in operator. In this
case, overload resolution is used to determine which operator function
or built-in operator is to be invoked to implement the operator.
Therefore, the operator notation is first transformed to the
equivalent function-call notation as summarized in Table 15 (where #
denotes one of the operators covered in the specified subclause).
However, the operands are sequenced in the order prescribed for the
built-in operator (7.6).
Why can I overload and use ++ operator in LHS and RHS while + one works just in LHS mode?
class B {
public:
string operator ++ () { return "hello"; }
string operator + () { return "hello2"; }
};
int main ()
{
B b;
string s = +b ;
s = b+ ; // compile error syntax error : ';'
s = b++;
s = ++b;
return 0;
}
Overloaded operators can only be used with the same syntax as the corresponding built-in ones. The built-in ++ is defined as either a prefix or postfix operator; the built-in + is only defined as a prefix operator (and of course as a binary operator).
Note that your code won't compile even without the b+ line, since you're missing a postfix version of ++:
string operator ++ (int) { return "postfix"; }
Why I can overload and use ++ operator in LHS and RHS
Your code actually produces two errors:
main.cpp:16:12: error: expected expression
s = b+ ; // compile error syntax error : ';'
^
main.cpp:18:10: error: cannot increment value of type 'B'
s = b++;
~^
So you actually haven't overloaded the post-increment operator, only the pre-increment operator. Your question remains, however, since you could overload post-increment if you wanted to but C++ does not offer any similar syntax for overloading a postfix unary plus operator.
C++ does not change the way operators in expressions are parsed based on operator overloads. It will only allow you to overload operators that already exist, and those operators will be parsed exactly as if operator overloads do not exist. It's only after parsing that C++ will then look around for operator overloads to figure out what the parsed expression means. Thus C++ offers a way to overload a post-increment operator because it already handles parsing the post-increment operator, but it does not already handle parsing a postfix plus operator.
Limiting C++ operator overloads to existing operators was done because it is simpler to implement a parser if the parser doesn't have watch out for arbitrary uses of operators. That doesn't mean it can't be done, however. The language Swift, for example, allows arbitrary operator overloading for binary, prefix unary, and postfix unary operators, including creating completely new operators.
In c++ I implemented an integer class and I overloaded operator ^ to be the power function.
integer integer::operator^ (const integer& rhs){
return integer(pow(this->.i, rhs.i));
}
This is working correctly for two operands.
integer i1, i2, i3 ;
i4 = i1 ^ i2 ^ i3;
The value of i4 is wrong mathematically because associativity required right-to-left. How can I solve this problem? How do I change associativity?
I got reasonable answers and I learn:
-We can't change associativity or priority of an operator.
-Good is Not to overload operators to do something conceptually different to
the built-in versions
-Even compiler can't support; it hard to implement!
You cannot change the associativity or priority of an operator in C++ by overloading it. These rules are hardwired into the language syntax.
The C++ standard says (§13.5.6, emphasis mine):
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. It is not possible to change the precedence, grouping, or number of operands of operators.
The meaning of the operators =, (unary) &, and , (comma), predefined for each type, can be changed [...]
Not only is the ^ operator left-associative, but it also has a very low precedence. The correct precedence for a power operator should be higher than the multiplication (so priority 4 or better on this table), but it has priority 10--this means that even additions and subtractions are evaluated before it. 1 + 2 ^ 3 * 4 will be parsed as (1 + 2) ^ (3 * 4), while a mathematically correct power operator should parse as 1 + (2 ^ 3) * 4.
If the associativity or priority of an operator could be modified, a huge, huge syntactical mess would ensue. My humble opinion is that you should not try to overload the ^ operator to use it as a power operator. I would rather make a power method on the class.
I am reading the C++ Primer, in the overloaded operation chapter, the author gave an example:
// member binary operator: left-hand operand bound to implicit this pointer
Sales_item& Sales_item::operator+=(const Sales_item&);
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
then, the author explained:
This difference matches the return types of these operators when applied to arithmetic types: Addition yields an rvalue and compound assignment returns a reference to the left-hand operand.
I'm not quite sure about "compound assignment returns a reference to the left-hand operand". Can anyone elaborate on that, and relevant things, please?
It means that you can do something like the following
a = 1;
(a += 1) += 1;
and the result will be a == 3. This is because the left most call to += modifies a and then
returns a reference to it. Then the next += operates on the reference to a and again adds a number to it.
On the other hand, the normal + operator returns a copy of the result, not a reference to one of the arguments. So this means that an expression such as a + a = 3; is illegal.
a = a + b;
is also
a += b;
which is equivalent to
a.operator+= (b)
operator += supports compound assignment:
(a += b) += c;
is equivalent to
a.operator+= (b).operator+= (c);
The last line would not be possible if a value was returned instead of an rvalue.
Consider the following:
c = a + b;
is also
c = a.operator+ (b);
writing
a.operator+ (b) = c;
has no effect because the value of a is not changed.
While trying to learning operator overloading, I read the following statements from C++ Primer. Frankly speaking, I do not quite understand what does the message that these statements want to deliver. The examples include defining both member binary operator and nonmember binary operator. Is there any difference when using them?
Ordinarily we define the arithmetic and relational operators as nonmember functions and we define assignment operators as members:
Sales_item& Sales_item:: operator (const Sales_item&)
Sales_item operator_(const Sales_item&, const Sales_item&);
Both addition and compound assignment are binary operators, yet these functions define a different number of parameters. The reason for the discrepancy is the this pointer.
Yes, there is a difference in actual use. In particular, when you overload an operator as a non-member function, conversions can be applied to either operand (or both operands). When you overload a binary operator with a member function, conversions can only be applied to the right operand.
This can lead to some oddities. For example, consider writing a "bignum" package and you wanted to overload operator+ to handle bignums. If you overload it as a member function, you get an oddity like this:
int x = 2;
bignum y = 3;
bignum z;
z = y + x; // works fine.
z = x + y; // doesn't work: x isn't a bignum, and can/won't be converted to one
If, instead, you overload operator+ using a non-member function, both of the operations will work (presuming you have a constructor to create a bignum from an int, which you'd almost certainly want).
A few operators (particularly assignment operators, such as =, +=, -=, etc.) are special. A conversion creates a temporary object, and assigning to a temporary object 1) isn't allowed, and 2) wouldn't make sense or accomplish much anyway. Therefore, when you're overloading assignment operators, you always use a member function.