The purpose of this quiz is to give you a chance to focus your knowledge of overloading operators in C++.
Name three operators which cannot be overloaded at all.
operators that cannot be overloaded include ., .*, sizeof, and :: in both unary and binary forms.
How does one go about deciding whether an operator should be a member function or a non-member? (Hint: There is a three rule process to the decision.)
1) Does it have to be a member operator? (I.E. =, [], and ().) 2) Is its left-hand operand of the type being overloaded for? Then it must not be a member! 3) Otherwise, it is up to the programmer's discretion.
TRUE ✓ | FALSE ✗ | The meaning of an operator can be changed when overloading it. | ||
---|---|---|---|---|
TRUE ✗ | FALSE ✓ | When overloading an operator, we can easily change the arity of the operator. | ||
TRUE ✗ | FALSE ✓ | One can change the precedence of an operator when overloading it. | ||
TRUE ✓ | FALSE ✗ | The associativity of an overloaded operator, however, cannot be changed. |
When overloading the ____ operator, it is important to consider if the programmer will want to/should be allowed to use this operator as an Lvalue (value usable on the left side of an assignment). If so, the operator should return a ____ the data in question. If not, the operator should return a copy of the data and the operator function should be made ____. Often, we do both (so that the operation can work on both regular and constant objects).
operators which can be, but are seldom, overloaded include new (which is used to allocate memory on the heap for single objects), delete[] (used to deallocate heap memory for whole arrays), and , (which normally returns the result of its right-hand operand unchanged).
Show the code for an overloaded + operator for a Rational class. (Make sure you've accounted for reasonable compatibility with the built-in types.)
Either just: Rational operator+(const Rational & left, const Rational & right) { return Rational{left.numer*right.denom + left.denom*right.numer, left.denom*right.denom}; } or we could do three overloads assuming an explicit constructor that makes Rational objects from lone integers.
What is the ~ operator normally used for? What sort of clever use might you put it to on a Rational class? Is this a good idea?
~ is normally used to change 0s to 1s in an integer memory location and vice versa. We often say it is flipping the bits. We might use it for either reciprocal because of its flipping heritage or for decimal approximation because it resembles "approximately equal to" from math. Since there are two perfectly reasonable uses for this operator in a Rational class, we should probably refrain from overloading it at all to avoid confusion.
When overloading either ++ or --, how does the programmer tell the compiler that you desire to change the pre- or post- version of the operator? (i.e. How can you distinguish between x++ and ++x during overloading?)
The postfix version of these operators takes a plain int argument that is unnamed and unused inside the function definition. Its entire purpose is to make the signatures of the two function forms different so the compiler can tell them apart. That is: Rational operator++(int) const; // post-increment Rational & operator++(void) const; // pre-increment
Recalling that the statement:
y = 2 + x;
is translated by the compiler into:
y.operator=(operator+(2,x));
Show the operator function call syntax for each of the following statements. (Whenever possible, assume the operator is a class member and the variable an object. If an operator is NOT overloadable, don't use the function call syntax!)
y = 4*x+z/7;
y.operator=(operator*(4,x).operator+(z.operator/(7)));
x << 5 << "Hi";
x.operator<<(5).operator<<("Hi");
y = x++;
y.operator=(x.operator(0));
(7 == x) ? (&u) : (-::p);
operator==(7,x) ? u.operator&() : ::p.operator-();
q += 7 & t;
q.operator+=(operator&(7,t));
7 >> h > 2;
operator>>(7,h).operator>(2);
y(12 + 7 - *u - !a + z[u^t] | j++) = 10 % +w < (z , m);
y.operator()(operator-(12+7,u.operator*()).operator-(a.operator!()) .operator+(z.operator[](u.operator^(t))) .operator|(j.operator++(0))).operator=( operator<(10 % w.operator+(),z.operator,(m)));
Name three operators which must be member functions when overloaded.
These would be assignment (=), function call (()), subscript ([]), and arrow (->).
TRUE ✗ | FALSE ✓ | When overloading operators, we can also create our own new operators. |
---|
Why can't we overload the ~ operator in an assignment form just like * (*=), + (+=), and - (-=)? (i.e. Why isn't there a ~= operator?)
~ is only a unary operator. The other mentioned operators are both unary and binary depending on context. It is their binary versions that have "with assignment" variants -- not their unary versions! Thus there can be no unary "with assignment" variants.