Объекты как переменные-члены в классе в C++

Я хотел бы знать, как лучше всего обрабатывать экземпляры объектов как переменные-члены другого класса. После прочтения разных сообщений кажется, что в целом следует избегать ссылок на объекты в качестве переменных-членов, но я не уверен, что использование указателей является хорошим решением. Другая возможность состоит в том, чтобы иметь ссылки const в качестве параметра конструктора класса, а затем использовать конструктор копирования для инициализации переменных-членов.

  • Каковы эмпирические правила, чтобы справиться с этой ситуацией?
  • Как насчет использования share_ptr в качестве переменных-членов?
  • Что, если переменная-член ссылается на абстрактный класс? В этом случае есть ли другие альтернативы указателям или ссылкам?

РЕДАКТИРОВАТЬ:

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

 class Client{

        // reference to Abstract strategy
        void execute(){
             strategy.doStuff();
        }
 }

 class AbstractStrategy{

 public:
      virtual void doStuff() = 0;
 }

 class ConcreteStrategy{
      void doStuff(){}
 }

Поскольку AsbtractStrategy имеет чисто виртуальные функции, кажется, что единственный способ сделать его членом Client — использовать указатели или ссылки. Есть ли лучшие решения?


person gcswoosh    schedule 12.03.2015    source источник
comment
Нет никаких эмпирических правил. Это полностью зависит от контекста. Не могу ответить на это.   -  person Lightness Races in Orbit    schedule 12.03.2015
comment
Хотя есть это   -  person Lightness Races in Orbit    schedule 12.03.2015
comment
Мне очень нравятся умные указатели. Они делают C++ реальной средой для работы.   -  person LovaBill    schedule 12.03.2015


Ответы (2)


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

Класс Person должен иметь член age в виде числа, а не указателя на единицу, но residence человека может быть указателем для ссылки на объект в наборе жилых помещений. И не всегда необходимо, чтобы человек управлял местом жительства или использовал интеллектуальные указатели, слой данных места жительства может быть полностью независимым от слоя человека, было бы мало смысла удалять место жительства вместе с человеком, вместо этого он должен просто стать вакантным.

Все зависит от того, что вам нужно, должен ли объект быть чем-то, иметь что-то или просто ссылаться на что-то внешнее.

Имейте в виду, что косвенность имеет свою цену. Вот почему не имеет особого смысла реализовывать элемент age в виде указателя, люди не живут очень долго, вы можете обойтись одним байтом для хранения возраста, и вы ничего не выиграете, если у вас есть коллекция возрастов. и вы ссылаетесь по одному для каждого человека, поскольку указатель обычно составляет 4 или 8 байтов плюс байт, на который он ссылается, вы тратите память и время ЦП на получение данных по этому адресу памяти. Но резиденция может быть крупным объектом, плюс она не тесно связана с человеком, поэтому имеет смысл реализовать резиденцию человека в виде указателя. И в то время как интеллектуальный указатель удалит место жительства по мере удаления человека, обычный указатель просто позволит вам отменить регистрацию этого человека из ссылок на жителей дома в деструкторе человека.

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

Что касается абстрактных классов - поскольку они не могут быть созданы, вы не можете иметь их в качестве объекта-члена. И поскольку идея состоит в том, чтобы определить интерфейс, вы, скорее всего, будете указателем и будете использовать виртуальную диспетчеризацию и полиморфизм. Обратите внимание, что помимо агрегации вы также можете использовать наследование. Если для каждого объекта существует одна стратегия, и она есть у каждого объекта, то и агрегация, и наследование сделают свое дело. В случае, если некоторые объекты имеют несколько объектов, а другие не имеют ни одного, вы можете выбрать несвязанный дизайн, упомянутый в предыдущем абзаце. Также обратите внимание, что использование наследования Strategy::doStuff() станет частью виртуальной таблицы этого объекта, что означает, что каждый объект этого конкретного типа будет выполнять один и тот же код, а при использовании агрегации или другой связи стратегия может быть установлена ​​для каждого экземпляра. база.

person dtech    schedule 12.03.2015

На ваш вопрос нет единого ответа. Фактор, который необходимо учитывать, — это время жизни объекта. Если объект А «содержит» объект Б в той или иной форме, то объект Б должен жить дольше, чем объект А или «Происходят Плохие Вещи».

Интеллектуальные указатели (shared_ptr, unique_ptr) позволяют объекту A применять правило, согласно которому объект B не может быть удален до тех пор, пока с ним не будет покончено с объектом A, поэтому они являются хорошей идеей.

Копирование объекта B в объект A также обеспечивает необходимую гарантию продолжительности жизни объекта B, но вы должны знать, что теперь есть два отдельных объекта B. Приемлемо ли это, решать вам.

С указателями и ссылками вообще проблематично, потому что A не контролирует время жизни B, но иногда общая структура программы означает, что это не проблема.

Резюме: узнайте время жизни вашего объекта и узнайте, какие инструменты вам доступны.

person Dale Wilson    schedule 12.03.2015