Как реализовать композицию классов в C ++? - PullRequest
6 голосов
/ 06 декабря 2009

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

Давайте посмотрим на Википедию пример :

class Car
{
  private:
    Carburetor* itsCarb;
  public:   
    Car() {itsCarb=new Carburetor();}
    virtual ~Car() {delete itsCarb;}
};

Итак, это один из способов - у нас есть указатель на объект в качестве частного члена. Можно переписать это так:

class Car
{
  private:
    Carburetor itsCarb;
};

В этом случае у нас есть объект как частный член. (Кстати, правильно ли я называю эту сущность объектом с точки зрения терминологии?)

Во втором случае не обязательно неявно вызывать конструктор по умолчанию (если нужно вызвать конструктор не по умолчанию, это можно сделать в списке инициализатора) и деструктор. Но это не большая проблема ...

И, конечно, в некоторых аспектах эти два случая различаются более заметно. Например, во втором случае запрещено вызывать неконстантные методы экземпляра Carburetor из константных методов класса Car ...

Есть ли какие-нибудь "правила", чтобы решить, какой из них использовать? Я что-то пропустил?

Ответы [ 5 ]

8 голосов
/ 06 декабря 2009

В этом случае сам объект является приватным членом. (Кстати, называя эту сущность объектом, я пишу с точки зрения терминологии?)

Да, вы можете сказать «объект» или «экземпляр» класса.

Вы также можете говорить о включении элемента данных «по значению» вместо «по указателю» (потому что «по указателю» и «по значению» - это обычный способ говорить о передаче параметров, поэтому я ожидаю, что люди поймут эти условия, применяемые к членам данных).

Есть ли какие-нибудь "правила", чтобы решить, какой из них использовать? Я что-то пропустил?

Если экземпляр совместно используется несколькими контейнерами, то каждый контейнер должен включать его по указателю вместо значения; например, если у сотрудника есть экземпляр Boss, включите указатель Boss по указателю, если несколько экземпляров Employee совместно используют одного и того же Босса.

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

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

Еще одна причина для включения по указателю заключается в том, что это может позволить вам изменить реализацию элемента данных без перекомпиляции контейнера. Например, если Car и Carburetor были определены в двух разных DLL, возможно, вы захотите включить Carburetor по указателю: потому что тогда вы сможете изменить реализацию Carburetor, установив другой Carburetor.dll, не перестраивая Car.dll .

8 голосов
/ 06 декабря 2009

Я предпочитаю первый случай, потому что второй требует, чтобы вы #include Carburettor.h в Car.h. Поскольку Carburettor является частным участником, вам не нужно включать его определение где-то еще, кроме как в настоящий код реализации Car. Использование класса Carburettor, безусловно, является деталью реализации, и внешним объектам, которые используют ваш объект Car, не нужно беспокоиться о включении других необязательных зависимостей. Используя указатель, вам просто нужно использовать предварительное объявление Carburettor в Car.h.

3 голосов
/ 06 декабря 2009

Состав: предпочитайте член, когда это возможно. Используйте указатель, когда необходим полиморфизм или когда используется прямое объявление. Конечно, без умного указателя при использовании указателей необходимо ручное управление памятью.

1 голос
/ 06 декабря 2009

Если Carb имеет тот же срок службы, что и Car, то, по моему мнению, форма без указателя лучше. Если вам нужно заменить Carb in Car, я бы выбрал версию указателя.

0 голосов
/ 06 декабря 2009

Как правило, версия без указателя проще в использовании и обслуживании.

Но в некоторых случаях вы не можете его использовать. Например, если в автомобиле имеется несколько карбюраторов, и вы хотите поместить их в массив, а конструктору Carburetor требуется аргумент: вам нужно создать их с помощью new и, таким образом, сохранить их как указатели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...