Как получить доступ к защищенному методу в базовом классе из производного класса? - PullRequest
9 голосов
/ 12 января 2011

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

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' */
    }
};

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

Спасибо за вашу помощь.: О)

Ответы [ 6 ]

10 голосов
/ 12 января 2011

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

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

6 голосов
/ 12 января 2011

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

Однако, если ваш код должен делать это так, как вы пытаетесь, и это не разрешено, вам нужно либо сделать foo () публичной, либо сделать Derived другом Base.

2 голосов
/ 24 октября 2016

Одним из решений было бы объявление статической защищенной функции в Base, которая перенаправляет вызов закрытой / защищенной функции (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 виртуальным или нет, или он является частным или защищенным.

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

1 голос
/ 10 сентября 2013

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

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

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

0 голосов
/ 12 января 2011

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

--- откуда?

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

РЕДАКТИРОВАТЬ: Статья MSDN на спецификаторе защищенного доступа.

0 голосов
/ 12 января 2011

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

...