Общий защищенный член данных в базовом классе? - PullRequest
6 голосов
/ 11 июня 2010

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

Вот конкретный пример:

class Base{
public:
   virtual void foo() = 0;
   void printData();
protected:
   std::vector<std::string> mData;
}

class Dr1 : public Base{
public:
   virtual void foo(); //could change mData
}

class Dr2 : public Base{
public:
   virtual void foo(); //could change mData
}

Если я помещаю mData в Dr1 и Dr2 как закрытый член, тогда мне нужно поместить их в оба из них, и у меня не может быть printData () в Base, так как printData () нужен доступ к mData, если я не сделаю printData () виртуальные и имеют идентичные функции как в Dr1, так и в Dr2, что не имеет особого смысла для меня.

Есть ли лучший способ подойти к этому без использования защищенного члена? Спасибо.

Ответы [ 5 ]

9 голосов
/ 11 июня 2010

Это открыто для значительных аргументов. Разрешение данных быть protected было добавлено в C ++ в значительной степени потому, что Марк Линтон хотел, чтобы они были для библиотеки Windowview Interviews, которую он разрабатывал. Казалось, что он вполне вписывается в остальную часть дизайна C ++, поэтому (очевидно) Бьярне согласился с этой идеей. Через несколько лет Марк запретил любое использование защищенных элементов данных в интервью из-за количества ошибок, возникших в результате их использования. Через некоторое время после этого Барбара Лисков выступила с докладом о теоретических и практических проблемах со всем понятием.

В Проектирование и развитие C ++ Бьярне приходит к выводу, что: «Оглядываясь назад, я думаю, что protected - это случай, когда я позволил« хорошим аргументам »и ​​моде преодолеть мои лучшие суждения и мои правила большой палец для принятия новых функций. "

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

3 голосов
/ 11 июня 2010

Один из подходов, который следует рассмотреть, - это сделать mData частной и добавить в Base защищенные методы, которые обеспечивают общие манипуляции с данными, которые затем могут использоваться Dr1 и Dr2.

Но во многих случаях имеет смысл оставить mData защищенным участником. Лучший подход будет во многом зависеть от деталей вашего класса.

1 голос
/ 11 июня 2010

Я пришел к выводу, что защищенные данные так же плохи, как публичные данные в классе.Если вам когда-нибудь понадобится изменить защищенные данные, вы нарушите все классы, полученные из базы.Эти производные классы являются клиентами вашего базового класса, как и обычные «публичные» пользователи.Я предлагаю написать защищенные функции доступа, которые могут вызывать производные классы.Это дает вам все преимущества общедоступных функций-членов: вы можете изменять свою реализацию, не прерывая работу клиентов, и при необходимости легко добавлять инструментарий и проверку ошибок.

0 голосов
/ 11 июня 2010

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

class Base {
protected:
    // figure out what interface you want for your subclasses:
    // do they need the whole enchilada? or can you give them
    // a few more targeted kinds of modification routines?
    // one example:
    void add_data(const std::string& d) { mData.push_back(d); }
private:
    std::vector<std::string> mData;
};
0 голосов
/ 11 июня 2010

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

Причины, по которым я не ставлю это:

  1. Если ваш интерфейс (абстрактный базовый класс) заморожен, то вам придется использовать это хранилище или нарушить совместимость для ваших пользователей.
  2. Чтобы пользователи не заставляли #include <string> и <vector>.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...