【问题标题】:Access a derived private member function from a base class pointer to a derived object [duplicate]从基类指针访问派生私有成员函数到派生对象[重复]
【发布时间】:2011-08-23 03:14:42
【问题描述】:

可能重复:
Why can i access a derived private member function via a base class pointer to a derived object?

#include <iostream>
using namespace std;

class B {
public:
  virtual void fn1(void) {cout << "class B : fn  one \n"; }
  virtual void fn2(void) {cout << "class B : fn  two \n"; }
};

class D: public B {
    void fn1(void) {cout << "class D : fn one \n"; }
private:
    void fn2(void) {cout << "class D : fn two \n"; }
};

int main(void)
{
    B *p = new D;

    p->fn1();
    p->fn2();
}

为什么p-&gt;fn2() 调用派生类函数,即使fn2D 中是私有的?

【问题讨论】:

  • C++99 中的第 11.6 节。 D 中的 fn1 也将默认为私有,因为未指定。
  • @Georg:垃圾问题标题如何帮助破坏 Stack Overflow 的有趣示例。这个问题的标题很好。
  • @Tomalak Geret'kal 您可以随时编辑其他问题以使用相同的标题。我现在正在考虑这样做。你怎么看?
  • @Georg:干杯:D 我投票结束这个问题作为 dup,心情沉重。对不起巴拉斯。
  • @Hosam:已经完成了。

标签: c++ inheritance polymorphism access-modifiers


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    调用p-&gt;fn2() 在运行时根据p 指向的对象类型进行评估。在编译时,编译器将p-&gt;fn2() 调用视为对B::fn2() 的调用,并且由于B::fn2() 是公开的,因此编译器不会只报告错误。只有在运行时才会评估实际的函数调用 D::fn2()

    这并没有违反Encapsulation 原则,这是C++ 的一个特性,称为Run-time PolymorphismDynamic Polymorphism

    【讨论】:

      【解决方案3】:

      当您执行p = new D 时,p-&gt;__vfptr 现在指向D 的虚函数表的开头。由于这发生在运行时,因此访问说明符不会发挥作用。

      【讨论】:

      • 虚函数表是一个实现细节。
      • vptr & vtbl 是编译器的实现细节,所以解释它们不是最好的方法。
      【解决方案4】:

      来自wikipedia

      在 OOP 中,当派生类继承 基类,派生对象 类可以被称为(或强制转换)为 要么是基类类型,要么 派生类类型。如果有 被重写的基类方法 派生类,方法调用 行为模棱两可。

      虚拟和虚拟的区别 non-virtual 解决了这种歧义。 如果有问题的功能是 在基类中指定为“虚拟” 然后是派生类的函数 将被调用(如果存在)。如果它 不是虚拟的,基类的 函数将被调用。

      HTH。

      【讨论】:

      • 这不能回答 OP 关于访问修饰符的问题。
      • 而且我们不在 SO 上写签名。
      猜你喜欢
      • 2011-04-06
      • 2011-01-27
      • 2016-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多