Как вызвать защищенную функцию-член в Base, в экземпляре Base, из Derived?

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

class B {
protected:
    void f ();
};

class D : public B {
public:
    void g (B* other) {
        other->f(); /* Error: B::f() is protected */
    }
};

Но есть ли решения? Что, если мы действительно хотим вызвать этот базовый метод для этого объекта? В конце концов, с этим не будет никаких проблем, ведь мы можем гарантировать, что other действительно является B?


person Félix Faisant    schedule 27.05.2014    source источник
comment
тот же ответ, что и для вызова частного метода в другом классе. сделайте это общедоступным или подружитесь или подумайте еще раз, вам действительно нужно это назвать?   -  person Bryan Chen    schedule 28.05.2014
comment
Вы пробовали класс друзей?   -  person Stefan    schedule 28.05.2014
comment
Если это академический вопрос, вы можете использовать дружбу, чтобы решить его. Если это происходит из реального приложения, вам нужно подвергнуть сомнению свой дизайн. Придумайте лучший дизайн, который не приведет вас к этому исправлению.   -  person R Sahu    schedule 28.05.2014
comment
Проблема friend заключается в модульности. B не нужно знать, какие классы будут его подклассами и будут использовать его защищенные функции. Это не совсем конкретный вопрос, потому что я знаю, что мог бы принять другой дизайн. Но в моем случае я не возражаю против вызова функций базового класса, подобных этому.   -  person Félix Faisant    schedule 28.05.2014


Ответы (3)


Примечание. Прямой (и рекомендуемый) способ включить что-либо, поскольку это сделать унаследованный класс friend базового класса; это означает, что он будет иметь доступ к своим protected и private частям.


Я хочу немного изменить правила

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

class B {
  protected:
    void f ();
};

<суп>

class D : public B {
  public:
    void g (B * other) {
      (other->*&D::f) (); // legal
    }
};

Как работает этот легальный и полнофункциональный хак?

Несмотря на то, что Стандарт говорит, что нам не разрешено проверять B::f изнутри D, нам, конечно, разрешено смотреть на D::f; что то же самое (унаследовано), поскольку мы не объявляли еще один f внутри D.

Наш хак состоит в том, чтобы взять адрес D::f, полагаясь на тот факт, что его тип действительно является указателем на функцию-член внутри B, и использовать этот адрес для вызова функция на other.

Другой (семантически) эквивалентный способ написать фрагмент:

void (B::*hack)() = &D::f; (other->*hack) ();

Примечание. Технически мы не углубляемся в защищенное содержимое B, мы просто полагаемся на тот факт, что содержимое, доступ к которому осуществляется через D::f, оказывается таким же, как и в B::f. Мы по-прежнему играем по правилам, установленным Стандартом, просто немного нарушаем их.

person Filip Roséen - refp    schedule 28.05.2014
comment
Спасибо ! Я нахожу ваше решение довольно чистым, потому что ему не нужно ничего изменять в иерархии классов, в отличие от решения friend. - person Félix Faisant; 28.05.2014
comment
Мне интересно, есть ли в этом неопределенное (или, по крайней мере, неопределенное) поведение. Я ожидал бы этого, потому что мы более или менее вызываем метод типа D для объекта типа B. С другой стороны, я предполагаю, что высоки шансы, что это всегда будет работать так, как ожидалось, даже если UB. - person Ignitor; 14.01.2019

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

См. мой ответ на исходный вопрос с примерами кода.

person Clemens Sielaff    schedule 24.10.2016

Вы можете сделать class D friend из class B:

class B {
friend class D;
protected:
    void f ();
};
person alain    schedule 27.05.2014