Класс Disc_quote
можно было бы определить без его собственной версии функции net_price()
. В данном случае класс Disc_quote
наследовал бы функцию net_price()
от класса Quote
.
Однако такой проект позволил бы пользователям писать бессмысленный код. Пользователь мог бы создать объект типа Disc_quote
, предоставив количество и объем скидки. Передача объекта класса Disc_quote
такой функции, как print_total()
, задействовала бы версию функции net_price()
из класса Quote
. Вычисляемая цена не включила бы скидку, предоставляемую при создании объекта. Такое поведение не имеет никакого смысла.
Тщательный анализ этого вопроса показывает, что проблема не только в том, что неизвестно, как определить функцию net_price()
. Практически следовало бы запретить пользователям создавать объекты класса Disc_quote
вообще. Этот класс представляет общую концепцию скидки на книги, а не конкретную стратегию скидок.
Для воплощения этого намерения (и однозначного уведомления о бессмысленности функции net_price()
) определим функцию net_price()
как = 0
(т.е. как раз перед точкой с запятой, завершающей объявление). Часть = 0
может присутствовать только в объявлении виртуальной функции в теле класса:
//
//
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; //
double discount = 0.0; //
};
Подобно прежнему классу Bulk_item
, класс Disc_quote
определяет стандартный конструктор и конструктор, получающий четыре параметра. Хотя объекты этого типа нельзя создавать непосредственно, конструкторы в классах, производных от класса Disc_quote
, будут использовать конструкторы Disc_quote()
для построения части Disc_quote
своих объектов. Конструктор с четырьмя параметрами передает первые два конструктору Quote()
, а двумя последними непосредственно инициализирует собственные переменные-члены discount
и quantity
. Стандартный конструктор инициализирует эти члены значениями по умолчанию.
Следует заметить, что определение для чистой виртуальной функции предоставить нельзя. Однако тело функции следует определить вне класса. Поэтому нельзя предоставить в классе тело функции, для которой использована часть = 0
.
Класс, содержащий (или унаследовавший без переопределения) чистую виртуальную функцию, является Disc_quote
определяет функцию net_price()
как чистую виртуальную, нельзя определить объекты типа Disc_quote
. Можно определить объекты классов, производных от Disc_quote
, если они переопределят функцию net_price()
:
//
//
Disc_quote discounted; //
Bulk_quote bulk; //
Классы, унаследованные от класса Disc_quote
, должны определить функцию net_price()
, иначе они также будут абстрактными.
Теперь можно повторно реализовать класс Bulk_quote
так, чтобы он происходил от класса Disc_quote
, а не непосредственно от класса Quote
: