Как открыть защищенный метод базового класса из производного класса?

вот пример кода, который раздражает меня:

class Base {
  protected:
    virtual void foo() = 0;
};

class Derived : public Base {
  private:
    Base *b; /* Initialized by constructor, not shown here
                Intended to store a pointer on an instance of any derived class of Base */

  protected:
    virtual void foo() { /* Some implementation */ };
    virtual void foo2() {
      this->b->foo(); /* Compilator sets an error: 'virtual void Base::foo() is protected' */
    }
};

Как получить доступ к защищенной переопределенной функции?

Спасибо за помощь. : o)

6 ответов


защищенные члены в базовом классе доступны только текущему объекту.
Таким образом, вы можете позвонить this->foo(), но вам не разрешается звонить this->b->foo(). Это не зависит от того,Derived обеспечивает реализацию foo или нет.

причина этого ограничения заключается в том, что в противном случае было бы очень легко обойти защищенный доступ. Вы просто создаете класс, как Derived, и вдруг у вас также есть доступ к частям других классов (как OtherDerived), которые должны быть недоступны для посторонних лиц.


обычно вы делаете это с помощью Base::foo(), который ссылается на базовый класс текущего экземпляра.

однако, если ваш код должен сделать это так, как вы пытаетесь, и это не разрешено, вам нужно либо сделать Foo() общедоступным, либо сделать производным другом базы.


одним из решений было бы объявить статическую защищенную функцию в Base перенаправляет вызов на функцию private / protected (foo в Примере).

допустим:

class Base {
protected:
    static void call_foo(Base* base) { base->foo(); }
private:
    virtual void foo() = 0;
};

class Derived : public Base {
private:
    Base* b;
protected:
    virtual void foo(){/* Some implementation */};
    virtual void foo2()
    {
        // b->foo(); // doesn't work
        call_foo(b); // works
    }
};

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

кроме того, этот метод работает независимо от того,foo виртуальная или нет, будет ли он закрытым или защищенным.

здесь является ссылкой на текущую версию кода выше и здесь другая версия той же идеи с немного большей бизнес-логикой.


это немного хрупко, но с классами, которые вы определили здесь, это не сработает?

virtual void foo2() {
  reinterpret_cast<Derived *>(this->b)->foo(); 
}

reinterpret_cast указывает на VTABLE для базового объекта и вызывает его через этот метод доступа членов.


вы вызываете базовые функции явно с помощью оператора scope (Base::foo ()). Но в этом случае базовый класс не определяет foo (это чисто виртуальный), поэтому на самом деле нет функции для выполнения, когда вы говорите this->b->foo(); Так как b является указателем на Base и не производным.


как вы получаете доступ к защищенному функция перекрытая?

--- откуда?

вы можете получить доступ к защищенному члену только через наследование (кроме методов того же класса). Скажем, например, у вас есть class Derived1, который наследует от Derived, то объекты Derived1 можно назвать foo().

EDIT:статья MSDN на спецификаторе защищенного доступа.