![](/img/trans.png)
[英]why can't I cast a pointer to Derived class member function to the same but of class Base?
[英]Why can I access a derived private member function via a base class pointer to a derived object?
#include<iostream>
using namespace std;
class base
{
public:
virtual void add() {
cout << "hi";
}
};
class derived : public base
{
private:
void add() {
cout << "bye";
}
};
int main()
{
base *ptr;
ptr = new derived;
ptr->add();
return 0;
}
输出是bye
我对这是如何实现没有问题。 我理解你使用vtable和派生的vtable包含新的add()函数的地址。 但是当我尝试在类外部访问它时,add()是私有的,不应该编译器生成错误吗? 不知怎的,这似乎不对。
add()
只在私人derived
,但你有静态类型为base*
-这样的访问限制base
应用。
一般来说,你甚至不能在编译时知道指向base
的指针的动态类型是什么,它可以例如根据用户输入而改变。
这是根据C ++03§11.6 :
虚函数的访问规则(第11节)由其声明确定,并且不受稍后覆盖它的函数规则的影响。
[...]使用表达式的类型在调用点检查访问,该表达式用于表示调用成员函数的对象[...]。 成员函数在定义它的类中的访问通常是未知的。
访问修饰符(例如public
, private
和protected
仅在编译期间强制执行。 通过指向基类的指针调用函数时,编译器不知道指针指向派生类的实例。 根据编译器可以从该表达式推断出的规则,此调用有效。
降低派生类中成员的可见性通常是语义错误。 现代编程语言(如Java和C#)拒绝编译此类代码,因为在基类中可见的成员始终可以通过基指针在派生类中访问。
为Georg的回答添加一点:
请记住,编译器无法控制,也无法保证派生类的任何内容。 例如,我可以将我的类型发布到库中,并从一个全新的程序中派生出来。 如何知道库编译器知道派生可能有不同的访问说明符? 编译库时,派生类型不存在。
为了支持这一点,编译器必须在运行时知道访问说明符,并在尝试访问私有成员时抛出异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.