Thinking about the question in this detail reveals that our problem is not just that we don’t know how to define net_price
. In practice, we’d like to prevent users from creating Disc_quote
objects at all. This class represents the general concept of a discounted book, not a concrete discount strategy.
We can enforce this design intent—and make it clear that there is no meaning for net_price
—by defining net_price
as a pure virtual function. Unlike ordinary virtuals, a pure virtual function does not have to be defined. We specify that a virtual function is a pure virtual by writing = 0
in place of a function body (i.e., just before the semicolon that ends the declaration). The = 0
may appear only on the declaration of a virtual function in the class body:
// class to hold the discount rate and quantity
// derived classes will implement pricing strategies using these data
class Disc_quote : public Quote {
public:
Disc_quote() = default;
Disc_quote(const std::string& book, double price,
std::size_t qty, double disc):
Quote(book, price),
quantity(qty), discount(disc) { }
double net_price(std::size_t) const = 0;
protected:
std::size_t quantity = 0; // purchase size for the discount to apply
double discount = 0.0; // fractional discount to apply
};
Like our earlier Bulk_item
class, Disc_quote
defines a default constructor and a constructor that takes four parameters. Although we cannot define objects of this type directly, constructors in classes derived from Disc_quote
will use the Disc_quote
constructors to construct the Disc_quote
part of their objects. The constructor that has four parameters passes its first two to the Quote
constructor and directly initializes its own members, discount
and quantity
. The default constructor default initializes those members.
It is worth noting that we can provide a definition for a pure virtual. However, the function body must be defined outside the class. That is, we cannot provide a function body inside the class for a function that is = 0
.