Class authors often define auxiliary functions, such as our add
, read
, and print
functions. Although such functions define operations that are conceptually part of the interface of the class, they are not part of the class itself.
We define nonmember functions as we would any other function. As with any other function, we normally separate the declaration of the function from its definition (§ 6.1.2, p. 206). Functions that are conceptually part of a class, but not defined inside the class, are typically declared (but not defined) in the same header as the class itself. That way users need to include only one file to use any part of the interface.
Ordinarily, nonmember functions that are part of the interface of a class should be declared in the same header as the class itself.
read
and print
FunctionsThe read
and print
functions do the same job as the code in § 2.6.2 (p. 75) and not surprisingly, the bodies of our functions look a lot like the code presented there:
// input transactions contain ISBN, number of copies sold, and sales price
istream &read(istream &is, Sales_data &item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
ostream &print(ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.avg_price();
return os;
}
The read
function reads data from the given stream into the given object. The print
function prints the contents of the given object on the given stream.
However, there are two points worth noting about these functions. First, both read
and print
take a reference to their respective IO class types. The IO classes are types that cannot be copied, so we may only pass them by reference (§ 6.2.2, p. 210). Moreover, reading or writing to a stream changes that stream, so both functions take ordinary references, not references to const
.
The second thing to note is that print
does not print a newline. Ordinarily, functions that do output should do minimal formatting. That way user code can decide whether the newline is needed.
add
FunctionThe add
function takes two Sales_data
objects and returns a new Sales_data
representing their sum:
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs; // copy data members from lhs into sum
sum.combine(rhs); // add data members from rhs into sum
return sum;
}
In the body of the function we define a new Sales_data
object named sum
to hold the sum of our two transactions. We initialize sum
as a copy of lhs
. By default, copying a class object copies that object’s members. After the copy, the bookNo, units_sold
, and revenue
members of sum
will have the same values as those in lhs
. Next we call combine
to add the units_sold
and revenue
members of rhs
into sum
. When we’re done, we return a copy of sum
.
Exercise 7.6: Define your own versions of the add
, read
, and print
functions.
Exercise 7.7: Rewrite the transaction-processing program you wrote for the exercises in § 7.1.2 (p. 260) to use these new functions.
Exercise 7.8: Why does read
define its Sales_data
parameter as a plain reference and print
define its parameter as a reference to const
?
Exercise 7.9: Add operations to read and print Person
objects to the code you wrote for the exercises in § 7.1.2 (p. 260).
Exercise 7.10: What does the condition in the following if
statement do?
if (read(read(cin, data1), data2))