2010-08-31 108 views
29
#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为什么我可以通过派生对象的基类指针访问派生的私有成员函数?

我没有用,这是如何实现的问题。我知道你使用vtables,并且派生的vtable包含新的add()函数的地址。但是,当我试图在类之外访问它时,add()是否是私有的,不应该编译器生成错误?不知怎的,这看起来不正确。

+4

覆盖和访问说明符是正交概念。 – sbi 2010-08-31 19:28:33

+0

vtables是一个实现细节。 – 2011-05-11 09:24:37

回答

32

add()是唯一的民营的derived,但静态类型你已经是base* - 这样的base的访问限制。
一般来说,你甚至在编译时甚至不知道指向base的指针的动态类型是什么,它可能是,例如,根据用户输入进行更改。

这是每C++ 03§11.6

的访问规则的虚拟功能(第11)是由它的声明来确定和用于功能不受规则稍后覆盖它。
[...]在调用点使用用于表示成员函数被调用的对象的表达式类型检查Access。成员函数在其定义的类中的访问一般是未知的。

+0

+1 - 感谢您对我的回答的澄清评论。 – 2010-08-31 16:17:23

+0

@Georg Fritzsche你能否给我一个从你复制这个链接的地方链接到C++ 03的链接。我谷歌搜索,但没有找到,想研究C + + – 2014-05-25 17:46:41

+0

@Jai:[“我在哪里可以找到当前的C或C++标准文档?”](http://stackoverflow.com/questions/81656/where-do-i-find -the-current-c-or-c-standard-documents) – 2014-06-02 10:35:44

5

要一点点添加到乔治的回答是:

请记住,编译器无法控制,也无法保证有关派生类的任何信息。例如,我可以将我的类型发布到一个库中,并通过一个全新的程序从中得到它。库编译器应该如何知道派生可能具有不同的访问说明符?编译库时,派生类型不存在。

为了支持这一点,编译器必须在运行时知道访问说明符,并在尝试访问私有成员时抛出异常。

10

访问修饰符,例如public,privateprotected仅在编译期间执行。当通过指向基类的指针调用函数时,编译器不知道指针指向派生类的实例。根据规则,编译器可以从这个表达式推断出,这个调用是有效的。

降低派生类中成员的可见性通常是语义错误。现代编程语言(如Java和C#)拒绝编译此类代码,因为在基类中可见的成员总是可以通过基指针在派生类中访问。

+1

+1最佳答案。 – 2011-05-11 09:25:28

相关问题