Вопрос по private-members, protected, c++ – @chtz забыл статическое приведение.

4

, что базовый классA определяет защищенный член. Производный классB использует этот член.

class A
{
public:
  A(int v) : value(v) { }

protected:
  int value;
};

class B : public A
{
public:
  B(int v) : A(v) { }
  void print() const;
  void compare_and_print(const A& other) const;
};

ФункцияB::print просто берет значение текущего члена и печатает его:

void B::print() const
{
  std::cout << "Value: " << value << "\n";
}

Другая функция-член,B::compare_and_print, берет примерA, проверяет их значения и печатает максимум обоих:

void B::compare_and_print(const A& other) const
{
  auto max_value = std::max(value, other.value);
  std::cout << "Max value: " << max_value << "\n";
}

Еслиother были экземпляром классаBэто не будет проблемой. Но функция хотела бы работать с любым видомA экземпляров. Это, к сожалению, не компилируется. Вот что говорит об этом Clang:

test.cpp:27:42: error: 'value' is a protected member of 'A'
  auto max_value = std::max(value, other.value);
                                         ^
test.cpp:9:7: note: can only access this member on an object of type 'B'
  int value;
      ^
1 error generated.

Это ограничение звучит для меня нелогично. Однако я не собираюсь оспаривать стандарт C ++ по этому поводу (тем не менее меня интересует обоснование этого решения).

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

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

Как я могу включить использование защищенного члена базового класса производным классом без экспорта члена через API?

РЕДАКТИРОВАТЬ: Некоторые связанные вопросы:

Доступ к защищенным членам в производном классеКак получить доступ к защищенным членам в производном классе?

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

Возможно, такой модели не может быть, я признаю.

Фактически, целью моего вопроса было получить ответ с объектно-ориентированной точки зрения. Решения, которые я знаю (кастинг, декларация друга) - это просто технические приемы. Если только такие уловки позволяют мне что-то делать, я, вероятно, делаю это неправильно. Итак, актуальный вопрос будет, что я делаю не так? Зачем мне жертвовать защитой от прицелов или использовать технические хитрости? Spiros
@GrahamS вся цель защищенных членов - позволить производным классам использовать этих членов, что мне и нужно. Базовый класс даже не должен знать, какие производные классы существуют. ИспользуяfriendМне нужно редактировать базовый класс всякий раз, когда новый производный класс нуждается в доступе к защищенному члену, что является нарушением принципа открытого-закрытого. Это не чистое решение, которое я ищу. (Кстати, у меня могут быть некоторые данные в базовом классе, которые я тоже хочу скрыть от производного класса, сделав его закрытым) Spiros
Делаяfriend? songyuanyao
@PeteBecker Это не дубликат. Этот вопрос спрашивает «как», в то время как этот вопрос спрашивает «почему». xskxzr
не могли бы вы оставить только один из источников? Это облегчает следовать Raxvan

Ваш Ответ

2   ответа
3

использующая указатели членов (без приведения, без копирования):

void B::compare_and_print(const A& other) const
{
  auto max_value = std::max(value, other.*(&B::value));
  std::cout << "Max value: " << max_value << "\n";
}
Хорошо, это upvote, я поражен! Это было так странно для меня, я спросилконкретный вопрос о том, почему это нормально, Проверьте это;) YSC
@ YSC Я думаю, что нашел безопасный вариант chtz
0

struct A_Helper : public A
{
    static int GetProtectedValue(const A & a)
    {
        return static_cast<const A_Helper&>(a).Value;
    }
};

Вы можете получить его, используя его где угодноA_Helper::GetProtectedValue(a)

В вашем случае вы могли бы броситьother вconst B& (черезstatic_cast или жеreinterpret_cast) но вы не знаете, если экземплярother имеет типB, С этой приведенной ценностью люди, читающие код, будут предполагать, чтоother имеет типB и может вставить код, который вызывает чтение / запись в «случайную» память.

Считайте, что классB есть еще один членvalue_B а такжеother имеет типC, С помощьюstatic_cast<const B&>(other).value_B является неопределенным поведением.

Это все еще позволило бы произвольному коду получить доступ к защищенному члену, это просто делает его менее видимым, верно? Защита от запутывания? :-) Spiros
Почему это работает, но доступ напрямую изB не? chtz
@chtz забыл статическое приведение. Raxvan

Похожие вопросы