Разработка класса b_1.
Напишем вначале интерфейсную часть класса B_1.
// Файл B_1.h
class B_1
{
public:
B_1();
B_1(const A&, int m);
B_1(const B& rhs);
void display();
private:
A a_;
int m_;
};
Замечание. В интерфейс нового класса включен один из возможных вариантов реализации конструктора с параметрами: B_1(const A&, int m);
Перейдем к реализации класса B_1. Прежде всего, следует принять во внимание, что реализация должна находиться в отдельном файле с расширением .cpp. Выберем для него полное имя B_1.cpp. Будем учитывать много альтернативность возможных решений.
Начнем с рассмотрения возможных реализаций конструктора умолчания.
Конструктор умолчания.
Первый вариант реализации.
B_1 :: B_1() : m_(0) { }
Второй вариант реализации
B_1 :: B_1() : m_(0), a_() { }
Обсуждение. Это эквивалентные реализации. В первом варианте отсутствуют элементы инициализации для пользовательского поля a_. В этом случае компилятор должен вызвать конструктор умолчания класса, к которому относится пользовательское поле (в рассматриваемом примере это класс A). Если бы в нашем примере в классе A не был бы предусмотрен такой конструктор, то было бы выдано сообщение об ошибке.
Конструктор с параметрами
Здесь можно также рассмотреть две реализации. В первой из них инициализация выполняется в строке инициализации, а во второй инициализация заменяется присваиваниями в теле конструктора.
Первый вариант реализации
B_1 :: B_1(const A& a, int m) : a_(a), m_(m) { }
Второй вариант реализации
B_1 :: B_1(const A& a, int m) {
a_ = a;
m_ = m; }
Обсуждение. Первый вариант реализации обладает заметными преимуществами по сравнению со вторым вариантом. Дело в том, что инициализация в этом случае выполняется вызовом конструктора копирования класса A. Этот вызов будет иметь место при компиляции выражения a_(a), находящегося в строке инициализации. Сложнее будет обстоять дело при компиляции присваивания вида a_ = a; Такое присваивание возможно только в том случае, когда уже существует объект, стоящий слева от оператора присваивания. Для этой цели компилятор вызывает конструктор умолчания класса A.
Конструктор копирования.
Ограничимся одним вариантом реализации – использования строки инициализации.
B_1 :: B_1(const B_1& rhs) : a_(rhs.a_), m_(rhs.m_) { }
Рекомендация 1. В конструкторах предпочитайте инициализацию присваиванию.
Рекомендация 2. В строке инициализации записывайте отдельные элементы списка инициализации в том порядке, в котором появляются инициализируемые поля в объявлении класса. Заметим, что именно в этом порядке записаны элементы инициализации в рассмотренном примере. Дело в том, элементы строки инициализации выполняются в том порядке, в каком они объявляются, а в не том порядке, в котором они встречаются в строке инициализации.
Функция вывода на дисплей. display()
В теле этой функции следует вначале с помощью функции A :: display() вывести поля внутреннего объекта A :: a_, а затем собственного поля m_. Приведем реализацию этой функции.
void B_1 :: display() { a_.disply(); cout << “m = ” << m_ << endl; }
