12.2.4 Отношения принадлежности.

   


Назад  |  Вперёд

Если используется отношение принадлежности, то существует два основных способа представления объекта класса X:

Если значение указателя не будет меняться и вопросы эффективности не волнуют, эти способы эквивалентны:

           class X {
               //...
           public:
               X(int);
               //...
           };

           class C {
                X a;
                X* p;
           public:
                C(int i, int j) : a(i), p(new X(j)) { }
                ~C()  { delete p; }
           };

В таких ситуациях предпочтительнее непосредственное членство объекта, как X::a в примере выше, потому что оно дает экономию времени, памяти и количества вводимых символов. Обратитесь также к $$12.4 и $$13.9.

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

           class C2 {
               X* p;
           public:
               C(int i) : p(new X(i))  { }
               ~C() { delete p; }

               X* change(X* q)
               {
                  X* t = p;
                  p = q;
                  return t;
               }
           };

Член типа указатель может также использоваться, чтобы дать возможность передавать "объект-элемент" в качестве параметра:

           class C3 {
             X* p;
           public:
              C(X* q) : p(q) {  }
              // ...
           }

Разрешая объектам содержать указатели на другие объекты, мы создаем то, что обычно называется "иерархия объектов". Это альтернативный и вспомогательный способ структурирования по отношению к иерархии классов. Как было показано на примере аварийного движущегося средства в $$12.2.2, часто это довольно тонкий вопрос проектирования: представлять ли свойство класса как еще один базовый класс или как член класса. Потребность в переопределении следует считать указанием, что первый вариант лучше. Но если надо иметь возможность представлять некоторое свойство с помощью различных типов, то лучше остановиться на втором варианте. Например:

           class XX : public X { /*...*/ };

           class XXX : public X { /*...*/ };

           void f()
           {
              C3* p1 = new C3(new X);     // C3 "содержит"  X
              C3* p2 = new C3(new XX);    // C3 "содержит"  XX
              C3* p3 = new C3(new XXX);   // C3 "содержит"  XXX
              //...
           }

Приведенные определения нельзя смоделировать ни с помощью производного класса C3 от X, ни с помощью C3, имеющего член типа X, поскольку необходимо указывать точный тип члена. Это важно для классов с виртуальными функциями, таких, например,как класс Shape ($$1.2.5), и для класса абстрактного множества ($$13.3).

Заметим, что ссылки можно применять для упрощения классов, использующих члены-указатели, если в течение жизни объекта-владельца ссылка настроена только на один объект, например:

            class C4 {
                X&  r;
            public:
                C(X& q) : r(q) { }
                // ...
           };

Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.