14.6.1. Инициализация члена, являющегося объектом класса

14.6.1. Инициализация члена, являющегося объектом класса

Что произойдет, если в объявлении _name заменить C-строку на тип класса string? Как это повлияет на почленную инициализацию по умолчанию? Как надо будет изменить явный копирующий конструктор? Мы ответим на эти вопросы в данном подразделе.

При почленной инициализации по умолчанию исследуется каждый член. Если он принадлежит к встроенному или составному типу, то такая инициализация применяется непосредственно. Например, в первоначальном определении класса Account член _name инициализируется непосредственно, так как это указатель:

newAcct._name = oldAcct._name;

Члены, являющиеся объектами классов, обрабатываются по-другому. В инструкции

Account newAcct( oldAcct );

оба объекта распознаются как экземпляры Account. Если у этого класса есть явный копирующий конструктор, то он и применяется для задания начального значения, в противном случае выполняется почленная инициализация по умолчанию.

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

В нашем примере у класса string есть явный копирующий конструктор, поэтому _name инициализируется с помощью его вызова. Копирующий конструктор по умолчанию для класса Account выглядит следующим образом (хотя явно он не определен):

inline Account::

Account( const Account &rhs )

{

_acct_nmbr = rhs._acct_nmbr;

_balance = rhs._balance;

// Псевдокод на C++

// иллюстрирует вызов копирующего конструктора

// для члена, являющегося объектом класса

_name.string::string( rhs._name );

}

Теперь почленная инициализация по умолчанию для класса Account корректно обрабатывает выделение и освобождение памяти для _name, но все еще неверно копирует номер счета, поэтому приходится кодировать явный копирующий конструктор. Однако приведенный ниже фрагмент не совсем правилен. Можете ли вы сказать, почему?

// не совсем правильно...

inline Account::

Account( const Account &rhs )

{

_name = rhs._name;

_balance = rhs._balance;

_acct_nmbr = get_unique_acct_nmbr();

}

Эта реализация ошибочна, поскольку в ней не различаются инициализация и присваивание. В результате вместо вызова копирующего конструктора string мы вызываем конструктор string по умолчанию на фазе неявной инициализации и копирующий оператор присваивания string - в теле конструктора. Исправить это несложно:

inline Account::

Account( const Account &rhs )

: _name( rhs._name )

{

_balance = rhs._balance;

_acct_nmbr = get_unique_acct_nmbr();

}

Самое главное - понять, что такое исправление необходимо. (Обе реализации приводят к тому, что в _name копируется значение из rhs._name, но в первой одна и та же работа выполняется дважды.) Общее эвристическое правило состоит в том, чтобы по возможности инициализировать все члены-объекты классов в списке инициализации членов.

Упражнение 14.13

* Для какого определения класса скорее всего понадобится копирующий конструктор? Представление Point3w, содержащее четыре числа с плавающей точкой.

* Класс matrix, в котором память для хранения матрицы выделяется динамически в конструкторе и освобождается в деструкторе.

* Класс payroll (платежная ведомость), где каждому объекту приписывается уникальный идентификатор.

* Класс word (слово), содержащий объект класса string и вектор, в котором хранятся пары (номер строки, смещение в строке).

Упражнение 14.14

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

(a) class BinStrTreeNode {

public:

// ...

private:

string _value;

int _count;

BinStrTreeNode *_leftchild;

BinStrTreeNode *_rightchild;

};

(b) class BinStrTree {

public:

// ...

private:

BinStrTreeNode *_root;

};

(c) class iMatrix {

public:

// ...

private:

int _rows;

int _cols;

int *_matrix;

};

(d) class theBigMix {

public:

// ...

private:

BinStrTree _bst;

iMatrix _im;

string _name;

vectorMfloat *_pvec;

};

Упражнение 14.15

Нужен ли копирующий конструктор для того класса, который вы выбрали в упражнении 14.3 из раздела 14.2? Если нет, объясните почему. Если да, реализуйте его.

Упражнение 14.16

Идентифицируйте в следующем фрагменте программы все места, где происходит почленная инициализация:

Point global;

Point foo_bar( Point arg )

{

Point local = arg;

Point *heap = new Point( global );

*heap = local;

Point pa[ 4 ] = { local, *heap };

return *heap;

}

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

5.4.2 Уточнение* Имени Члена

Из книги C++ автора Хилл Мюррей

5.4.2 Уточнение* Имени Члена – * Иногда называется также квалификацией. (прим. перев.)Иногда полезно делать явное различие между именами члнов класса и прочими именами. Для этого используется операция ::, «разрешения области видимости»:class x (* int m; public: int readm() (* return x::m; *) void setm(int


5.4.2 Уточнение* Имени Члена

Из книги Справочное руководство по C++ автора Страустрап Бьярн

5.4.2 Уточнение* Имени Члена – * Иногда называется также квалификацией. (прим. перев.)Иногда полезно делать явное различие между именами члнов класса и прочими именами. Для этого используется операция ::, «разрешения области видимости»:class x (* int m; public: int readm() (* return x::m; *) void setm(int


R.12.6 Инициализация

Из книги Реферат, курсовая, диплом на компьютере автора Баловсяк Надежда Васильевна

R.12.6 Инициализация Объект класса без конструкторов, без частных или защищенных членов, без виртуальных функций и без базовых классов можно инициализировать с помощью списка инициализаторов (§R.8.4.1). Объект класса с конструктором должен инициализироваться или иметь


Работа с формулой как с объектом

Из книги Windows Script Host для Windows 2000/XP автора Попов Андрей Владимирович

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


Связывание с нужным объектом каталога

Из книги TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security) автора Фейт Сидни М

Связывание с нужным объектом каталога Первым шагом для доступа к пространству имен любого каталога в целях получения информации о его объектах или изменения свойств этих объектов является связывание (binding) с нужным объектом ADSI.Рассмотрим вначале, каким образом


8.9.1 Инициализация RIP

Из книги Справочник по JavaScript автора Коллектив авторов

8.9.1 Инициализация RIP При запуске каждый маршрутизатор должен знать только о сети, к которой он подключен. Маршрутизатор RIP отправляет эти сведения широковещательной рассылкой на все соседние с ним в локальной сети маршрутизаторы. Кроме того, эти же сведения посылаются


Работа с объектом style

Из книги VBA для чайников автора Каммингс Стив

Работа с объектом style Объект style позволяет изменить стиль любого элемента Web-страницы, просто присвоив нужному свойству необходимое значение.paragraph1.style.fontSize = 7;Можно изменить геометрические размеры элемента:image1.style.height = "100mm";image1.style.width = "120mm";и его месторасположение:iamge1.style.top


Знакомство с объектом Application

Из книги C++. Сборник рецептов автора Диггинс Кристофер

Знакомство с объектом Application Как и во всех других VBA-приложениях, ключевым в объектной модели Word является объект Application. Другими словами, этот объект содержит все остальные объекты Word. Поскольку объект Application занимает центральное место в программировании на VBA в Word, вам


8.5. Гарантия единственности копии переменной-члена

Из книги C++ для начинающих автора Липпман Стенли

8.5. Гарантия единственности копии переменной-члена ПроблемаИмеется переменная-член, у которой должен быть только один экземпляр независимо от числа создаваемых экземпляров класса. Этот тип переменных-членов обычно называется статическими членами или переменными


2. Профессиональная деятельность члена вашей семьи

Из книги автора

2. Профессиональная деятельность члена вашей семьи Если вы не работаете на данный момент или вы – молодой человек без опыта работы, для вас следующий пункт. Возможно, кто-то из вашей семьи что-то очень хорошо делает. Например, ваш брат или сестра – фотограф, финансовый


8.5.4. Определение члена пространства имен

Из книги автора

8.5.4. Определение члена пространства имен Мы видели, что определение члена пространства имен может появиться внутри определения самого пространства. Например, класс matrix и константа pi появляются внутри вложенного пространства имен MatrixLib, а определения функций operator+() и


13.6.1. Тип члена класса

Из книги автора

13.6.1. Тип члена класса Указателю на функцию нельзя присвоить адрес функции-члена, даже если типы возвращаемых значений и списки параметров полностью совпадают. Например, переменная pfi – это указатель на функцию без параметров, которая возвращает значение типа int:int


14. Инициализация, присваивание и уничтожение класса

Из книги автора

14. Инициализация, присваивание и уничтожение класса В этой главе мы детально изучим автоматическую инициализацию, присваивание и уничтожение объектов классов в программе. Для поддержки инициализации служит конструктор - определенная проектировщиком функция (возможно,


14.1. Инициализация класса

Из книги автора

14.1. Инициализация класса Рассмотрим следующее определение класса:class Data {public:int ival;char *ptr;};Чтобы безопасно пользоваться объектом класса, необходимо правильно инициализировать его члены. Однако смысл этого действия для разных классов различен. Например, может ли ival