Друг вызывает виртуальный приватный метод - что должно произойти

У меня была ситуация, когда я хотел, чтобы класс друга вызывал закрытый метод, затем я хотел сделать этот метод виртуальным, чтобы вместо него вызывался метод класса - тогда я, конечно, понял, что дружба не наследуется. Таким образом, у нас есть ситуация, когда виртуальный метод означает, что метод производного класса должен быть вызван, но этот метод является частным, поэтому не может быть вызван. Который имеет приоритет?

Я проверил это на MSVC++ 2008 следующим образом

#include<iostream>

class Loner;

class Base
{
    friend Loner;
private:
    virtual void test(){std::cout << "Base" << std::endl;}
};

class Derived : public Base
{
private:
    virtual void test(){std::cout << "Derived" << std::endl;}
};

class Loner
{
public:
    void test(Base *base){base->test();}
};

int main()
{
    Loner loner;
    Derived derived;
    loner.test(&derived);
}

Выход был:

Derived

Таким образом, кажется, что виртуальная функция "побеждает" и дает частному члену доступ к не-другу - почти наследственное наследство!

Мой вопрос, кто-нибудь знает, если это правильное поведение? Когда я наконец доберусь до обновления версии своего компилятора или попробую GCC, это поведение может измениться?

ура

Фил

2 ответа

§ 11,5/1-2 ([class.access.virt]):

  1. Правила доступа (пункт 11) для виртуальной функции определяются ее объявлением и не зависят от правил для функции, которая впоследствии переопределяет ее.

  2. Доступ проверяется в точке вызова с использованием типа выражения, используемого для обозначения объекта, для которого вызывается функция-член...

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

По сути, здесь происходит то, что Base Виртуальная функция отправляет ее переопределения. Так что даже если вы не можете позвонить Derived переопределить статически (Derived::member), вы все еще можете получить Base::member позвонить вам, если у вас есть доступ к Base::member,

Вызов выполняется через указатель объекта со статическим типом Base* - это тип, с которым производятся проверки доступа. Эти проверки доступа происходят во время компиляции. поскольку Loner друг Base, компилятор в порядке с разрешением вызова base->test(),

Тем не менее, динамический тип объекта, который base указатель указывает на Derived, Во время выполнения дополнительных проверок доступа нет - выполняется вызов динамического типа, который отправляется через обычный механизм виртуального вызова.

Другие вопросы по тегам