Лучший способ использовать закрытую переменную-член базового класса в производном классе - PullRequest
0 голосов
/ 09 февраля 2020

У меня есть следующий код, где базовый класс определяет чисто виртуальную функцию, а производный класс определяет эту чисто виртуальную функцию для выполнения некоторых вычислений с закрытой переменной-членом базового класса var (var не будет изменено Однако). var - это обычно какая-то большая структура.

С точки зрения дизайна я читал, что, как правило, неодобрительно делать var защищенным элементом в этом случае. Будет ли лучший способ достичь того, чего я хочу, это просто передать var в качестве аргумента в virtual_func()?

Это вдохновило на второй вопрос. Что если я захочу изменить var в virtual_func? Это изменит ваш ответ?

class base
{
public:
  void search()
  {
    //virtual func in derived class must use var in base class, but not change var

    virtual_func();
  }

private:
  T var;
  virtual void virtual_func() = 0;
};

class derived : public base
{
  void virtual_func()
  {
    //does something with base class's var, but not alter it
  }
};

Ответы [ 3 ]

2 голосов
/ 09 февраля 2020

Бьярн Страуструп , в своей книге Проект и развитие C ++ обсуждает protected в разделе 13.9.

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

Следуя этим рекомендациям, вы должны оставить все данные базового класса private и добавить protected getter и функции установки для доступа к данным.

В зависимости от вашего варианта использования и стоимости копирования данных, ваш получатель может либо вернуть копию данных, либо ссылку (или постоянную ссылку) на них. Возврат неконстантной ссылки позволит вам изменить данные напрямую через присваивание (getVar() = newvar;) или изменить определенные c члены-данные класса. Возврат константной ссылки и использование функции сеттера инкапсулирует данные немного больше без чрезмерного раскрытия класса. Функция установки также позволит вам лучше контролировать изменения в var, включая выполнение любой проверки, которая может потребоваться.

1 голос
/ 09 февраля 2020

"С точки зрения дизайна я читал, что, как правило, неодобрительно делать var защищенным элементом в этом случае."

Кажется, неправильное представление о том, где вы читаете. Если вам нужно получить доступ к base::var в class derived, тогда лучшим решением будет принятие var как protected. Все остальное будет мешать инкапсуляции. Какой еще вариант использования protected отличается от требования, указанного в вашем вопросе. : -)

1 голос
/ 09 февраля 2020

Если вы не хотите делать var protected в базовом классе, вы можете добавить в базовую функцию-получатель public или protected, которую затем сможете вызвать в производном классе. Что-то вроде

T getVar() const { return var; }
...