Бьерн Страуструп - Язык программирования С++. Главы 5-7 - Объекты класса как члены

ОГЛАВЛЕНИЕ

5.5.4 Объекты класса как члены

Рассмотрим пример:
          class classdef {
             table members;
             int no_of_members;
             // ...
             classdef(int size);
             ~classdef();
          };
Цель этого определения, очевидно, в том, чтобы classdef содержал член, являющийся таблицей размером size, но есть сложность: надо обеспечить вызов конструктора table::table() с параметром size. Это можно сделать, например, так:
         classdef::classdef(int size)
            :members(size)
         {
            no_of_members = size;
            // ...
          }
Параметр для конструктора члена (т.е. для table::table()) указывается в определении (но не в описании) конструктора класса, содержащего член (т.е. в определении classdef::classdef()). Конструктор для члена будет вызываться до выполнения тела того конструктора, который задает для него список параметров.

Аналогично можно задать параметры для конструкторов других членов (если есть еще другие члены):

           class classdef {
             table members;
             table friends;
             int no_of_members;
             // ...
             classdef(int size);
             ~classdef();
           };
Списки параметров для членов отделяются друг от друга запятыми (а не двоеточиями), а список инициализаторов для членов можно задавать в произвольном порядке:
           classdef::classdef(int size)
               : friends(size), members(size), no_of_members(size)
           {
             // ...
           }
Конструкторы вызываются в том порядке, в котором они заданы в описании класса.

Подобные описания конструкторов существенны для типов, инициализация и присваивание которых отличны друг от друга, иными словами, для объектов, являющихся членами класса с конструктором, для постоянных членов или для членов типа ссылки. Однако, как показывает член no_of_members из приведенного примера, такие описания конструкторов можно использовать для членов любого типа.

Если конструктору члена не требуется параметров, то и не нужно задавать никаких списков параметров. Так, поскольку конструктор table::table() был определен со стандартным значением параметра, равным 15, достаточно такого определения:

          classdef::classdef(int size)
              : members(size), no_of_members(size)
          {
             // ...
          }
Тогда размер таблицы friends будет равен 15.

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

Рассмотрим вместо вхождения объектов класса в качестве членов традиционное альтернативное ему решение: иметь в классе указатели на члены и инициализировать члены в конструкторе:

           class classdef {
              table* members;
              table* friends;
              int no_of_members;
              // ...
           };

          classdef::classdef(int size)
          {
             members = new table(size);
             friends = new table;  // используется стандартный
                                   // размер table
             no_of_members = size;
             // ...
           }
Поскольку таблицы создавались с помощью операции new, они должны уничтожаться операцией delete:
          classdef::~classdef()
          {
            // ...
            delete members;
            delete friends;
          }
Такие отдельно создаваемые объекты могут оказаться полезными, но учтите, что members и friends указывают на независимые от них объекты, каждый из которых надо явно размещать и удалять. Кроме того, указатель и объект в свободной памяти суммарно занимают больше места, чем объект-член.