C++ Primer, Fifth Edition
Click here to view code image
Sales_data data;
data << cout; // if operator<< is a member of Sales_data
If these operators are members of any class, they would have to be members of
istream or ostream. However, those classes are part of the standard library, and
we cannot add members to a class in the library.
Thus, if we want to define the IO operators for our types, we must define them as
nonmember functions. Of course, IO operators usually need to read or write the
nonpublic data members. As a consequence, IO operators usually must be declared
as friends (§ 7.2.1, p. 269).
Exercises Section 14.2.1
Exercise 14.6: Define an output operator for your Sales_data class.
Exercise 14.7: Define an output operator for you String class you wrote
for the exercises in § 13.5 (p. 531).
Exercise 14.8: Define an output operator for the class you chose in exercise
7.40 from § 7.5.1 (p. 291).
14.2.2. Overloading the Input Operator >>
Ordinarily the first parameter of an input operator is a reference to the stream from
which it is to read, and the second parameter is a reference to the (nonconst) object
into which to read. The operator usually returns a reference to its given stream. The
second parameter must be nonconst because the purpose of an input operator is to
read data into this object.
The 
Sales_data
Input Operator
As an example, we’ll write the Sales_data input operator:
Click here to view code image
istream &operator>>(istream &is, Sales_data &item)
{
double price;  // no need to initialize; we'll read into price before we use
it
is >> item.bookNo >> item.units_sold >> price;
if (is)        // check that the inputs succeeded
item.revenue = item.units_sold * price;
else
www.it-ebooks.info
Convert pdf to editable ppt - C# Create PDF from PowerPoint Library to convert pptx, ppt to PDF in C#.net, ASP.NET MVC, WinForms, WPF
Online C# Tutorial for Creating PDF from Microsoft PowerPoint Presentation
convert pdf to powerpoint slides; convert pdf file to ppt online
Convert pdf to editable ppt - VB.NET Create PDF from PowerPoint Library to convert pptx, ppt to PDF in vb.net, ASP.NET MVC, WinForms, WPF
VB.NET Tutorial for Export PDF file from Microsoft Office PowerPoint
convert pdf into powerpoint online; convert pdf pages into powerpoint slides
C++ Primer, Fifth Edition
item = Sales_data(); // input failed: give the object the default
state
return is;
}
Except for the if statement, this definition is similar to our earlier read function (§
7.1.3, p. 261). The if checks whether the reads were successful. If an IO error
occurs, the operator resets its given object to the empty Sales_data. That way, the
object is guaranteed to be in a consistent state.
Note
Input operators must deal with the possibility that the input might fail; output
operators generally don’t bother.
Errors during Input
The kinds of errors that might happen in an input operator include the following:
• A read operation might fail because the stream contains data of an incorrect
type. For example, after reading bookNo, the input operator assumes that the
next two items will be numeric data. If nonnumeric data is input, that read and
any subsequent use of the stream will fail.
• Any of the reads could hit end-of-file or some other error on the input stream.
Rather than checking each read, we check once after reading all the data and before
using those data:
Click here to view code image
if (is)        // check that the inputs succeeded
item.revenue = item.units_sold * price;
else
item = Sales_data(); // input failed: give the object the default state
If any of the read operations fails, price will have an undefined value. Therefore,
before using price, we check that the input stream is still valid. If it is, we do the
calculation and store the result in revenue. If there was an error, we do not worry
about which input failed. Instead, we reset the entire object to the empty
Sales_data by assigning a new, default-initialized Sales_data object to item.
After this assignment, item will have an empty string for its bookNo member, and
its revenue and units_sold members will be zero.
Putting the object into a valid state is especially important if the object might have
been partially changed before the error occurred. For example, in this input operator,
we might encounter an error after successfully reading a new bookNo. An error after
reading bookNo would mean that the units_sold and revenue members of the old
www.it-ebooks.info
Online Convert PDF to Text file. Best free online PDF txt
RasterEdge PDF document conversion SDK provides reliable and effective .NET solution for Visual C# developers to convert PDF document to editable & searchable
convert pdf to powerpoint using; images from pdf to powerpoint
C++ Primer, Fifth Edition
object were unchanged. The effect would be to associate a different bookNo with
those data.
By leaving the object in a valid state, we (somewhat) protect a user that ignores the
possibility of an input error. The object will be in a usable state—its members are all
defined. Similarly, the object won’t generate misleading results—its data are internally
consistent.
Best Practices
Input operators should decide what, if anything, to do about error recovery.
Indicating Errors
Some input operators need to do additional data verification. For example, our input
operator might check that the bookNo we read is in an appropriate format. In such
cases, the input operator might need to set the stream’s condition state to indicate
failure (§ 8.1.2, p. 312), even though technically speaking the actual IO was
successful. Usually an input operator should set only the failbit. Setting eofbit
would imply that the file was exhausted, and setting badbit would indicate that the
stream was corrupted. These errors are best left to the IO library itself to indicate.
Exercises Section 14.2.2
Exercise 14.9: Define an input operator for your Sales_data class.
Exercise 14.10: Describe the behavior 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
Exercise 14.11: 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?
Click here to view code image
istream& operator>>(istream& in, Sales_data& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
s.revenue = s.units_sold * price;
return in;
}
Exercise 14.12: 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.
www.it-ebooks.info
C++ Primer, Fifth Edition
14.3. Arithmetic and Relational Operators
Ordinarily, we define the arithmetic and relational operators as nonmember functions
in order to allow conversions for either the left- or right-hand operand (§ 14.1, p.
555). These operators shouldn’t need to change the state of either operand, so the
parameters are ordinarily references to const.
An arithmetic operator usually generates a new value that is the result of a
computation on its two operands. That value is distinct from either operand and is
calculated in a local variable. The operation returns a copy of this local as its result.
Classes that define an arithmetic operator generally define the corresponding
compound assignment operator as well. When a class has both operators, it is usually
more efficient to define the arithmetic operator to use compound assignment:
Click here to view code image
// assumes that both objects refer to the same book
Sales_data
operator+(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;  // copy data members from lhs into sum
sum += rhs;             // add rhs into sum
return sum;
}
This definition is essentially identical to our original add function (§ 7.1.3, p. 261).
We copy lhs into the local variable sum. We then use the Sales_data compound-
assignment operator (which we’ll define on page 564) to add the values from rhs into
sum. We end the function by returning a copy of sum.
Tip
Classes that define both an arithmetic operator and the related compound
assignment ordinarily ought to implement the arithmetic operator by using
the compound assignment.
Exercises Section 14.3
Exercise 14.13: 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.
Exercise 14.14: Why do you think it is more efficient to define operator+
www.it-ebooks.info
C++ Primer, Fifth Edition
to call operator+= rather than the other way around?
Exercise 14.15: 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.
14.3.1. Equality Operators
Ordinarily, classes in C++ define the equality operator to test whether two objects are
equivalent. That is, they usually compare every data member and treat two objects as
equal if and only if all the corresponding members are equal. In line with this design
philosophy, our Sales_data equality operator should compare the bookNo as well as
the sales figures:
Click here to view code image
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() == rhs.isbn() &&
lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue;
}
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
return !(lhs == rhs);
}
The definition of these functions is trivial. More important are the design principles
that these functions embody:
• If a class has an operation to determine whether two objects are equal, it
should define that function as operator== rather than as a named function:
Users will expect to be able to compare objects using ==; providing == means
they won’t need to learn and remember a new name for the operation; and it is
easier to use the library containers and algorithms with classes that define the
== operator.
• If a class defines operator==, that operator ordinarily should determine
whether the given objects contain equivalent data.
• Ordinarily, the equality operator should be transitive, meaning that if a == b
and b == c are both true, then a == c should also be true.
• If a class defines operator==, it should also define operator!=. Users will
expect that if they can use == then they can also use !=, and vice versa.
• One of the equality or inequality operators should delegate the work to the
other. That is, one of these operators should do the real work to compare
objects. The other should call the one that does the real work.
www.it-ebooks.info
C++ Primer, Fifth Edition
Best Practices
Classes for which there is a logical meaning for equality normally should
define operator==. Classes that define == make it easier for users to use
the class with the library algorithms.
Exercises Section 14.3.1
Exercise 14.16: Define equality and inequality operators for your StrBlob
(§ 12.1.1, p. 456), StrBlobPtr (§ 12.1.6, p. 474), StrVec (§ 13.5, p.
526), and String (§ 13.5, p. 531) classes.
Exercise 14.17: 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.
14.3.2. Relational Operators
Classes for which the equality operator is defined also often (but not always) have
relational operators. In particular, because the associative containers and some of the
algorithms use the less-than operator, it can be useful to define an operator<.
Ordinarily the relational operators should
1. Define an ordering relation that is consistent with the requirements for use as
a key to an associative container (§ 11.2.2, p. 424); and
2. Define a relation that is consistent with == if the class has both operators. In
particular, if two objects are !=, then one object should be < the other.
Although we might think our Sales_data class should support the relational
operators, it turns out that it probably should not do so. The reasons are subtle and
are worth understanding.
We might think that we’d define < similarly to compareIsbn (§ 11.2.2, p. 425).
That function compared Sales_data objects by comparing their 
ISBN
s. Although
compareIsbn provides an ordering relation that meets requirment 1, that function
yields results that are inconsistent with our definition of ==. As a result, it does not
meet requirement 2.
The Sales_data == operator treats two transactions with the same 
ISBN
as
unequal if they have different revenue or units_sold members. If we defined the
www.it-ebooks.info
C++ Primer, Fifth Edition
< operator to compare only the 
ISBN
member, then two objects with the same 
ISBN
but
different units_sold or revenue would compare as unequal, but neither object
would be less than the other. Ordinarily, if we have two objects, neither of which is
less than the other, then we expect that those objects are equal.
We might think that we should, therefore, define operator< to compare each data
element in turn. We could define operator< to compare objects with equal isbns
by looking next at the units_sold and then at the revenue members.
However, there is nothing essential about this ordering. Depending on how we plan
to use the class, we might want to define the order based first on either revenue or
units_sold. We might want those objects with fewer units_sold to be “less
than” those with more. Or we might want to consider those with smaller revenue
“less than” those with more.
For Sales_data, there is no single logical definition of <. Thus, it is better for this
class not to define < at all.
Best Practices
If a single logical definition for < exists, classes usually should define the <
operator. However, if the class also has ==, define < only if the definitions of
< and == yield consistent results.
Exercises Section 14.3.2
Exercise 14.18: Define relational operators for your StrBlob,
StrBlobPtr, StrVec, and String classes.
Exercise 14.19: 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.
14.4. Assignment Operators
In addition to the copy- and move-assignment operators that assign one object of the
class type to another object of the same type (§ 13.1.2, p. 500, and § 13.6.2, p.
536), a class can define additional assignment operators that allow other types as the
right-hand operand.
As one example, in addition to the copy- and move-assignment operators, the library
vector class defines a third assignment operator that takes a braced list of elements
(§ 9.2.5, p. 337). We can use this operator as follows:
Click here to view code image
www.it-ebooks.info
C++ Primer, Fifth Edition
vector<string> v;
v = {"a", "an", "the"};
We can add this operator to our StrVec class (§ 13.5, p. 526) as well:
Click here to view code image
class StrVec {
public:
StrVec &operator=(std::initializer_list<std::string>);
// other members as in § 13.5 (p. 526)
};
To be consistent with assignment for the built-in types (and with the copy- and move-
assignment operators we already defined), our new assignment operator will return a
reference to its left-hand operand:
Click here to view code image
StrVec &StrVec::operator=(initializer_list<string> il)
{
// alloc_n_copy allocates space and copies elements from the given range
auto data = alloc_n_copy(il.begin(), il.end());
free();   // destroy the elements in this object and free the space
elements = data.first; // update data members to point to the new
space
first_free = cap = data.second;
return *this;
}
As with the copy- and move-assignment operators, other overloaded assignment
operators have to free the existing elements and create new ones. Unlike the copy-
and move-assignment operators, this operator does not need to check for self-
assignment. The parameter is an initializer_list<string> (§ 6.2.6, p. 220),
which means that il cannot be the same object as the one denoted by this.
Note
Assignment operators can be overloaded. Assignment operators, regardless of
parameter type, must be defined as member functions.
Compound-Assignment Operators
Compound assignment operators are not required to be members. However, we prefer
to define all assignments, including compound assignments, in the class. For
consistency with the built-in compound assignment, these operators should return a
reference to their left-hand operand. For example, here is the definition of the
www.it-ebooks.info
C++ Primer, Fifth Edition
Sales_data compound-assignment operator:
Click here to view code image
// member binary operator: left-hand operand is bound to the implicit this pointer
// assumes that both objects refer to the same book
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
Best Practices
Assignment operators must, and ordinarily compound-assignment operators
should, be defined as members. These operators should return a reference to
the left-hand operand.
14.5. Subscript Operator
Classes that represent containers from which elements can be retrieved by position
often define the subscript operator, operator[].
Exercises Section 14.4
Exercise 14.20: Define the addition and compound-assignment operators
for your Sales_data class.
Exercise 14.21: 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).
Exercise 14.22: Define a version of the assignment operator that can assign
a string representing an 
ISBN
to a Sales_data.
Exercise 14.23: Define an initializer_list assignment operator for
your version of the StrVec class.
Exercise 14.24: 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.
Exercise 14.25: Implement any other assignment operators your class
should define. Explain which types should be used as operands and why.
www.it-ebooks.info
C++ Primer, Fifth Edition
Note
The subscript operator must be a member function.
To be compatible with the ordinary meaning of subscript, the subscript operator
usually returns a reference to the element that is fetched. By returning a reference,
subscript can be used on either side of an assignment. Consequently, it is also usually
a good idea to define both const and nonconst versions of this operator. When
applied to a const object, subscript should return a reference to const so that it is
not possible to assign to the returned object.
Best Practices
If a class has a subscript operator, it usually should define two versions: one
that returns a plain reference and the other that is a const member and
returns a reference to const.
As an example, we’ll define subscript for StrVec (§ 13.5, p. 526):
Click here to view code image
class StrVec {
public:
std::string& operator[](std::size_t n)
{ return elements[n]; }
const std::string& operator[](std::size_t n) const
{ return elements[n]; }
// other members as in § 13.5 (p. 526)
private:
std::string *elements;   // pointer to the first element in the array
};
We can use these operators similarly to how we subscript a vector or array.
Because subscript returns a reference to an element, if the StrVec is nonconst, we
can assign to that element; if we subscript a const object, we can’t:
Click here to view code image
// assume svec is a StrVec
const StrVec cvec = svec; // copy elements from svec into cvec
// if svec has any elements, run the  string empty function on the first one
if (svec.size() && svec[0].empty())  {
svec[0] = "zero"; // ok: subscript returns a reference to a string
cvec[0] = "Zip";  // error: subscripting cvec returns a reference to
const
}
www.it-ebooks.info
Documents you may be interested
Documents you may be interested