c++有趣现象:private的成员函数可以在类的外部调用?

//在网上搜到这样一篇文章:

以下是从孙鑫的VC课程中摘抄的一段程序,
#include <iostream.h>
class base;
base * pbase;
class base
{
public:
base()
{pbase=this;}
virtual void fn()
{cout<<"base"<<endl;}
};
class derived:public base
{private:<br/> void fn()<br/> {cout<<"derived"<<endl;}
};
void main()
{
derived aa;
pbase->fn();
}

以上程序在VC和VC7中输出结果为 derived, 哈,居然private的成员函数可以在类的外部调用.

//我的问题是,难道这是真的吗?private的成员函数可以在类的外部调用.?
//还是这个private关键字不应该使用?

发现新大陆了呵呵,不错,但是,它并不是C++的缺陷或是被设计者所忽视的问题。

当我们使用虚函数的时候,它的访问规则是在声明的时候被确定的,而不是在被“子类重写”(overridden)的时候,虚函数的访问规则不会受到来自被重写的子类函数的影响,更进一步说,当某个对象A的引用B(特指间接访问)用来调用该对象的虚函数时,对于该对象A的一切声明信息,都取决于该对象的引用B,而不是这个引用所引用的对象A。

C++标准里有对该问题的具体说明:当一个子类函数通过基类的指针调用时,访问权限取决于基类对该函数的声明。

参考C++ Standard ISO/IEC 14882:2003(E) 第11.6节:

11.6 Access to virtual functions [class.access.virt]

The access rules (clause 11) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it. [Example:
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f()
{
D d;
B* pb = &d;
D* pd = &d;
pb->f(); //OK: B::f() is public,
// D::f() is invoked
pd->f(); //error: D::f() is private
}
—end example]

Access is checked at the call point using the type of the expression used to denote the object for which the member function is called (B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.

至少我们在程序编译时无法获知这个指针的值,它会指向何种位置。

经验:private仅仅是一个访问限定符,它只限定函数和数据不能被“直接”访问,而不担保这些函数和数据会被通过其他方法间接地访问到,在成员函数中返回一个类私有数据成员的引用也是这个道理。

另外,如果不是特殊的需要,一般来说,这并不是一个好的设计,有点自找麻烦的味道!
温馨提示:答案为网友推荐,仅供参考
第1个回答  推荐于2018-03-30
它并不是C++的缺陷或是被设计者所忽视的问题。

当我们使用虚函数的时候,它的访问规则是在声明的时候被确定的,而不是在被“子类重写”(overridden)的时候,虚函数的访问规则不会受到来自被重写的子类函数的影响,更进一步说,当某个对象A的引用B(特指间接访问)用来调用该对象的虚函数时,对于该对象A的一切声明信息,都取决于该对象的引用B,而不是这个引用所引用的对象A。

C++标准里有对该问题的具体说明:当一个子类函数通过基类的指针调用时,访问权限取决于基类对该函数的声明。

参考C++ Standard ISO/IEC 14882:2003(E) 第11.6节:

11.6 Access to virtual functions [class.access.virt]

The access rules (clause 11) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it. [Example:
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f()
{
D d;
B* pb = &d;
D* pd = &d;
pb->f(); //OK: B::f() is public,
// D::f() is invoked
pd->f(); //error: D::f() is private
}
—end example]

Access is checked at the call point using the type of the expression used to denote the object for which the member function is called (B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.

至少我们在程序编译时无法获知这个指针的值,它会指向何种位置。

经验:private仅仅是一个访问限定符,它只限定函数和数据不能被“直接”访问,而不担保这些函数和数据会被通过其他方法间接地访问到,在成员函数中返回一个类私有数据成员的引用也是这个道理。本回答被网友采纳
第2个回答  2013-06-07
当派生类将基类中public权限的虚函数重载并限制为private或protected时, 多态时直接使用基类指针将忽略派生类对该虚函数访问权限的更改,以基类函数的访问权限为依据调用该虚函数.
也就是说派生类的private失效了。
#include <iostream.h>
class base
{
public:
virtual void fn()
{cout<<"base"<<endl;}
};
class derived:public base
{private:<br/>void fn()<br/>{cout<<"derived"<< endl;}
};
void main()
{
base *aa = new derived;
aa->fn();
}
第3个回答  2013-06-07
如果private成员不可以间接被调用的话,就意味着这个成员永远不会被调用,getme?

所以有趣的不是这种情况,而是因这种情况产生了这种问题。
第4个回答  2013-06-07
这里pbase就是aa,不存在所谓类外调用private