У меня есть указатель базового класса, указывающий на объект производного класса. Метод foo () является общедоступным в базовом классе, но закрытым в производном классе. Базовый класс foo () является виртуальным. Поэтому, когда я вызываю foo () из указателя базового класса, Vptr Table имеет адрес производного класса foo (), НО его private в классе Derived … так как он вызывается. ??
Я понимаю полиморфизм во время выполнения, а также понимаю, что спецификаторы Access работают во время компиляции, а концепция Virtual работает во время выполнения. Так что не должно быть ошибки компилятора.
Мой вопрос: это дыра в петле, через которую мы можем вызывать закрытые методы класса Derived? или ожидается, что он будет вести себя таким образом.
Любое хорошее объяснение этого поведения.
Заранее большое спасибо.
КОД:
class A
{
public:
virtual void foo()
{
std::cout << "In A";
}
};class B:public A
{
private:
void foo()
{
std::cout << "In B ??? Its Private Method :-( ";
}
};
int main()
{
A* ptr = new B();
ptr->foo();
return 0;
}
Это приватный метод, но поскольку он виртуальный, его можно вызвать.
N3690 11,5 / 1
Правила доступа (пункт 11) для виртуальной функции определены его декларацией и не затронуты
правила для функции, которая позже переопределяет ее.
Почему это? поскольку
N3690 11,5 / 2
Доступ проверяется в точке вызова с использованием типа выражения, используемого для обозначения объекта, для которого
вызывается функция-член (B * в примере выше). Доступ функции-члена в классе в
который был определен (D в приведенном выше примере), как правило, не известен.
Уровень доступа — это концепция времени компиляции. Среда выполнения не знает, был ли объявлен метод private
или же public
, Это для вашего удобства.
На самом деле это хороший стандарт кодирования — virtual
метод должен быть в идеале public
в базовом классе и private
или же protected
в производных классах. Это заставит вызывающую сторону использовать интерфейсы, а не фактические типы (конечно, это не всегда практично, но полезно принимать во внимание).
Конкретный тип абстрагируется в вашем случае, как и должно быть. Базовый метод объявлен public
и вы вызываете его через указатель на базу, так что это разрешено.