In what ways does an overloaded operator differ from a built-in operator? In what ways are overloaded operators the same as the built-in operators?
Differ
- We can call an overloaded operator function directly.
- An overloaded operator function must either be a member of a class or have at least one parameter of class type.
- A few operators guarantee the order in which operands are evaluated. These overloaded versions of these operators do not preserve order of evaluation and/or short-circuit evaluation, it is usually a bad idea to overload them.
In particular, the operand-evaluation guarantees of the logical
AND
, logicalOR
, and comma operators are not preserved, Moreover, overloaded versions of&&
or||
operators do not preserve short-circuit evaluation properties of the built-in operators. Both operands are always evaluated.
Same
- An overloaded operator has the same precedence and associativity as the corresponding built-in operator.
Write declarations for the overloaded input, output, addition, and compound-assignment operators for
Sales_data
.
Both
string
andvector
define an overloaded == that can be used to compare objects of those types. Assumingsvec1
andsvec2
arevectors
that holdstrings
, identify which version of == is applied in each of the following expressions:
- (a)
"cobble" == "stone"
- (b)
svec1[0] == svec2[0]
- (c)
svec1 == svec2
- (d)
"svec1[0] == "stone"
(a) neither. (b) string
(c) vector
(d) string
Reference
Explain how to decide whether the following should be class members:
- (a) %
- (b) %=
- (c) ++
- (d) ->
- (e) <<
- (f) &&
- (g) ==
- (h) ()
(a) symmetric operator. Hence, non-member
(b) changing state of objects. Hence, member
(c) changing state of objects. Hence, member
(d) = () [] -> must be member
(e) non-member
(f) symetric , non-member
(g) symetric , non-member
(h) = () [] -> must be member
In exercise 7.40 from 7.5.1 (p. 291) you wrote a sketch of one of the following classes. Decide what, if any, overloaded operators your class should provide.
Such as Book
Define an output operator for your
Sales_data
class.
see Exercise 14.2.
Define an output operator for you
String
class you wrote for the exercises in 13.5 (p. 531).
Define an output operator for the class you chose in exercise 7.40 from 7.5.1 (p. 291).
see Exercise 14.5
Define an input operator for your Sales_data class.
see Exercise 14.2.
Describe the behaviour of the Sales_data input operator if given the following input:
-
(a) 0-201-99999-9 10 24.95
-
(b) 10 24.95 0-210-99999-9
-
(a) correct format.
-
(b) ilegal input. But
0-210-99999-9
will be converted to a float stored in this object. As a result, the data inside will be a wrong one. Output:10 24 22.8 0.95
check Test
What, if anything, is wrong with the following Sales_data input operator? What would happen if we gave this operator the data in the previous exercise?
istream& operator>>(istream& in, Sales_data& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
s.revenue = s.units_sold * price;
return in;
}
no input check. nothing happend.
Define an input operator for the class you used in exercise 7.40 from 7.5.1 (p. 291). Be sure the operator handles input errors.
see Exercise 14.5
Which other arithmetic operators (Table 4.1 (p. 139)), if any, do you think Sales_data ought to support? Define any you think the class should include.
Substraction, in order to be able to revert a previously addition. hpp | cpp | Test
Why do you think it is more efficient to define
operator+
to calloperator+=
rather than the other way around?
Discussing on SO.
Should the class you chose for exercise 7.40 from 7.5.1 (p. 291) define any of the arithmetic operators? If so, implement them. If not, explain why not.
Define equality and inequality operators for your
StrBlob
(12.1.1, p. 456),StrBlobPtr
(12.1.6, p. 474),StrVec
(13.5, p.526), andString
(13.5, p. 531) classes.
Should the class you chose for exercise 7.40 from 7.5.1(p. 291) define the equality operators? If so, implement them. If not, explain why not.
yes.see Exercise 14.15
Define relational operators for your
StrBlob
,StrBlobPtr
,StrVec
, andString
classes.
Should the class you chose for exercise 7.40 from 7.5.1 (p. 291) define the relational operators? If so, implement them. If not, explain why not.
yes.see Exercise 14.15
Define the addition and compound-assignment operators for your
Sales_data
class.
see Exercise 14.2.
Write the
Sales_data
operators so that+
does the actual addition and+=
calls+
. Discuss the disadvantages of this approach compared to the way these operators were defined in 14.3 (p. 560) and 14.4 (p.564).
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
Sales_data old_data = *this;
*this = old_data + rhs;
return *this;
}
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum;
sum.units_sold = lhs.units_sold + rhs.units_sold;
sum.revenue = lhs.revenue + rhs.revenue;
return sum;
}
Disadvantages: Both +
and +=
, uses an temporary object of Sales_data
. But it is no need for that.
Define a version of the assignment operator that can assign a
string
representing an ISBN to aSales_data
.
Define an initializer_list assignment operator for your version of the
StrVec
class.
Decide whether the class you used in exercise 7.40 from 7.5.1 (p. 291) needs a copy- and move-assignment operator. If so, define those operators.
Implement any other assignment operators your class should define. Explain which types should be used as operands and why.
see Exercise 14.24
Define subscript operators for your
StrVec
,String
,StrBlob
, andStrBlobPtr
classes.
Add increment and decrement operators to your
StrBlobPtr
class.
Define addition and subtraction for
StrBlobPtr
so that these operators implement pointer arithmetic (3.5.3, p. 119).
see Exercise 14.27
We did not define a
const
version of the increment and decrement operators. Why not?
Because ++
and --
change the state of the object. Hence , it's meaningless to do so.
Add dereference and arrow operators to your
StrBlobPtr
class and to theConstStrBlobPtr
class that you defined in exercise 12.22 from 12.1.6 (p. 476). Note that the operators inconstStrBlobPtr
must returnconst
references because thedata
member inconstStrBlobPtr
points to aconst vector
.
Our StrBlobPtr class does not define the copy constructor, assignment operator, or a destructor. Why is that okay?
Applying the Rule of 3/5: There is no dynamic allocation to deal with, so the synthesized destructor is enough. Moreover, no unique is needed. Hence, the synthesized ones can handle all the corresponding operations.
Define a class that holds a pointer to a
StrBlobPtr
. Define the overloaded arrow operator for that class.
How many operands may an overloaded function-call operator take?
An overloaded operator function has the same number of parameters as the operator has operands. Hence the maximum value should be around 256. (question on SO)
Define a function-object class to perform an if-then-else operation: The call operator for this class should take three parameters. It should test its first parameter and if that test succeeds, it should return its second parameter; otherwise, it should return its third parameter.
struct Test {
int operator()(bool b, int iA, int iB) {
return b ? iA : iB;
}
};
Write a class like
PrintString
that reads a line of input from anistream
and returns astring
representing what was read. If the read fails, return the emptystring
.
Use the class from the previous exercise to read the standard input, storing each line as an element in a vector.
Write a class that tests whether two values are equal. Use that object and the library algorithms to write a program to replace all instances of a given value in a sequence.
Write a class that tests whether the length of a given
string
matches a given bound. Use that object to write a program to report how many words in an input file are of sizes 1 through 10 inclusive.
Revise the previous program to report the count of words that are sizes 1 through 9 and 10 or more.
see Exercise 14.38
Rewrite the
biggies
function from 10.3.2 (p. 391) to use function-object classes in place of lambdas.
Why do you suppose the new standard added lambdas? Explain when you would use a lambda and when you would write a class instead.
IMO, lambda is quite handy to use. Lambda can be used when the functor is not used frequently nor complicated, whereas functor is supposed to call more times than lambda or quite complicated to implement as a lambda.
Using library function objects and adaptors, define an expression to
- (a) Count the number of values that are greater than 1024
- (b) Find the first string that is not equal to
pooh
- (c) Multiply all values by 2
std::count_if(ivec.cbegin(), ivec.cend(), std::bind(std::greater<int>(), _1, 1024));
std::find_if(svec.cbegin(), svec.cend(), std::bind(std::not_equal_to<std::string>(), _1, "pooh"));
std::transform(ivec.begin(), ivec.end(), ivec.begin(), std::bind(std::multiplies<int>(), _1, 2));
Using library function objects, determine whether a given
int
value is divisible by any element in a container ofint
s.
Write your own version of a simple desk calculator that can handle binary operations.
Write conversion operators to convert a
Sales_data
tostring
and todouble
. What values do you think these operators should return?
Explain whether defining these Sales_data conversion operators is a good idea and whether they should be explicit.
It's a bad idea to do so, because these conversion is misleading.explicit
should be added to prevent implicit conversion.
Explain the difference between these two conversion operators:
struct Integral {
operator const int(); // meaningless, it will be ignored by compiler.
operator int() const; // promising that this operator will not change the state of the obj
};
Determine whether the class you used in exercise 7.40 from 7.5.1 (p. 291) should have a conversion to
bool
. If so, explain why, and explain whether the operator should beexplicit
. If not, explain why not.
A conversion to bool can be useful for the class Date. But it must be an explicit one to prevent any automatic conversion.
Regardless of whether it is a good idea to do so, define a conversion to bool for the class from the previous exercise.
Show the possible class-type conversion sequences for the initializations of ex1 and ex2. Explain whether the initializations are legal or not.
struct LongDouble {
LongDouble(double = 0.0);
operator double();
operator float();
};
LongDouble ldObj;
int ex1 = ldObj; // error ambiguous: double or float?
float ex2 = ldObj; // legal
Show the conversion sequences (if any) needed to call each version of
calc
and explain why the best viable function is selected.
void calc(int);
void calc(LongDouble);
double dval;
calc(dval); // which calc?
best viable function: void calc(int)
. cause class-type conversion is the lowest ranked.
review the order:
- exact match
- const conversion
- promotion
- arithmetic or pointer conversion
- class-type conversion
Which
operator+
, if any, is selected for each of the addition expressions? List the candidate functions, the viable functions, and the type conversions on the arguments for each viable function:
struct LongDouble {
// member operator+ for illustration purposes; + is usually a nonmember LongDouble operator+(const SmallInt&); // 1
// other members as in 14.9.2 (p. 587)
};
LongDouble operator+(LongDouble&, double); // 2
SmallInt si;
LongDouble ld;
ld = si + ld;
ld = ld + si;
ld = si + ld;
is ambiguous. ld = ld + si
can use both 1 and 2, but 1 is more exactly. (in the 2, SmallInt need to convert to double
)
Given the definition of SmallInt on page 588, determine whether the following addition expression is legal. If so, what addition operator is used? If not, how might you change the code to make it legal?
SmallInt s1;
double d = s1 + 3.14;
ambiguous.
Fixed:
SmallInt s1;
double d = s1 + SmallInt(3.14);