Действие стандартного конструктора класса Sales_data подобно конструктору, получающему один строковый аргумент. Единственное отличие в том, что конструктор, получающий строковый аргумент, использует его для инициализации переменной-члена bookNo. Стандартный конструктор (неявно) использует стандартный конструктор типа string для инициализации переменной bookNo. Эти конструкторы можно переписать как единый конструктор с аргументом по умолчанию (см. раздел 6.5.1):

class Sales_data {

public:

 // определить стандартный конструктор как получающий строковый

 // аргумент

 Sales_data(std::string s = ""): bookNo(s) { }

 // остальные конструкторы без изменений

 Sales_data(std::string s, unsigned cnt, double rev):

            bookNo(s), units_sold(cnt), revenue(rev*cnt) { }

 Sales_data(std::istream &is) { read(is, *this); }

 // остальные члены, как прежде

};

Эта версия класса предоставляет тот же интерфейс, что и исходный из раздела 7.1.4. Обе версии создают тот же объект, когда никаких аргументов не предоставлено или когда предоставлен один строковый аргумент. Поскольку этот конструктор можно вызвать без аргументов, он считается стандартным конструктором класса.

Конструктор, предоставляющий аргументы по умолчанию для всех своих параметров, также считается стандартным конструктором.

Следует заметить, что, вероятно, не нужно использовать аргументы по умолчанию с конструктором Sales_data(), который получает три аргумента. Если пользователь предоставляет не нулевое количество проданных книг, следует также гарантировать, что пользователь предоставит и цену, по которой они были проданы.

Упражнения раздела 7.5.1

Упражнение 7.36. Следующий инициализатор ошибочен. Найдите и исправьте ошибку.

struct X {

 X(int i, int j): base(i), rem(base % j) { }

 int rem, base;

};

Упражнение 7.37. Используя версию класса Sales_data из этого раздела, определите, какой конструктор используется для инициализации каждой из следующих переменных, а также перечислите значения переменных-членов в каждом объекте:

Sales_data first_item(cin);

int main() {

 Sales_data next;

 Sales_data last("9-999-99999-9");

}

Упражнение 7.38. Конструктору, получающему аргумент типа istream&, можно предоставить объект cin как аргумент по умолчанию. Напишите объявление конструктора, использующего объект cin как аргумент по умолчанию.

Упражнение 7.39. Допустимо ли для конструктора, получающего строку, и конструктора, получающего тип istream&, иметь аргументы по умолчанию? Если нет, то почему?

Упражнение 7.40. Выберите одну из следующих абстракций (или абстракцию по собственному выбору). Определите, какие данные необходимы в классе. Предоставьте соответствующий набор конструкторов. Объясните свои решения.

(a) Book    (b) Date   (с) Employee

(d) Vehicle (e) Object (f) Tree

<p>7.5.2. Делегирующий конструктор</p>

Новый стандарт расширяет использование списков инициализации конструктора, позволяя определять так называемые делегирующие конструкторы (delegating constructor). Делегирующий конструктор использует для инициализации другой конструктор своего класса. Он "делегирует" некоторые (или все) свои задачи другому конструктору.

Подобно любому другому конструктору, делегирующий конструктор имеет список инициализации переменных-членов и тело функции. Список инициализации делегирующего конструктора содержит элемент, являющийся именем самого класса. Подобно другим инициализаторам переменных-членов класса, имя класса сопровождается заключенным в скобки списком аргументов. Список аргументов должен соответствовать другому конструктору в классе.

В качестве примера перепишем класс Sales_data так, чтобы использовать делегирующие конструкторы следующим образом:

class Sales_data {

public:

 // неделегирующий конструктор инициализирует члены из соответствующих

 // аргументов

 Sales_data(std::string s, unsigned cnt, double price):

            bookNo(s), units_sold(cnt), revenue(cnt*price) { }

 // все другие конструкторы делегируют к другому конструктору

 Sales_data(): Sales_data("", 0, 0) {}

Перейти на страницу:

Похожие книги