我最近在IBM site上看过这篇文章。以下是示例代码
#include "iostream"
class B {
public:
virtual void f()
{
std::cout<<"\n In class B";
}
};
class D : public B {
private:
int i;
void f()
{
std::cout<<"\n In class D i = "<<i;
}
public:
D(int i_num):i(i_num)
{}
};
int main() {
D dobj(10);
B* bptr = &dobj;
D* dptr = &dobj;
// valid, virtual B::f() is public,
// D::f() is called
bptr->f();
// error, D::f() is private
//dptr->f();
}
我们现在能够调用D.的私有函数了。我想知道这不是破解C ++封装吗?
P.S。 :请转到虚拟功能中的虚拟功能访问部分。我不知道为什么在粘贴时我没有得到确切的链接。
答案 0 :(得分:6)
在运行时评估调用bptr->f()
,具体取决于bptr
指向的对象类型。在编译时,编译将bptr->f()
调用视为对B::f()
的调用,并且由于B::f()
为public
,编译器不会仅报告错误。只有在运行时才会评估实际的函数调用D::f()
。
这不违反Encapsulation
原则这是C ++的一个名为Run-time Polymorphism
或Dynamic Polymorphism
您无法直接调用dptr->f()
,因为D::f()
在Private
访问说明符下声明,您无法从类外访问私有声明的成员。
答案 1 :(得分:2)
这是设计的。
B :: f 是公开的。允许用户通过 B 指针访问 f 。由于 f 是虚拟的,因此调用将被分派到派生类' f 。
但是 D :: f 是私密的,您无法通过指针访问 f D 。
答案 2 :(得分:2)
Access-specifiers是编译时构造,因此,编译器会在编译时(显然)根据对象(或指针)的 static 类型检测到任何违反访问规则的行为。在运行时无法检测到此类违规。
所以bptr->f()
有效,因为编译器发现bptr
的静态类型是B
,其public
函数{{1}已定义,因此表达式f()
通过了编译器的测试。因此它有效。
但是bptr->f()
不起作用,因为dptr->f()
的静态类型是dptr
,它具有私有函数D
,因此代码甚至不会编译!
现在它是否打破封装,是一个非常主观的问题,并会得到主观的答案。它完全取决于人们如何定义它以及直接从它流出的参数。没有一个通用的定义。我的个人意见是,如果语言允许的话,那么(这意味着)根据C ++社区,它不会破坏封装,或者如果确实如此,那么C ++允许它实现非常诺贝尔(否则是不可能的)。否则,我会说它只是另外一个C ++的错误,如下所示: