6

可能重复:
C++:覆盖公共\私有继承

class base {
public:
  virtual void doSomething() = 0;
};

class derived : public base {
private:   // <-- Note this is private

  virtual void doSomething()
  { cout << "Derived fn" << endl; }
};

现在,如果我执行以下操作:

base *b = new child;
b->doSomething();    // Calls the derived class function even though that is private

问题:

  1. 即使它是私有的,它也能够调用派生类函数。这怎么可能?

现在,如果我将继承访问说明符从 public 更改为 protected/private,则会出现编译错误:

'type cast' : conversion from 'Derived *' to 'base *' exists, but is inaccessible

注意:我知道继承访问说明符的概念。因此,在第二种情况下,由于它是私有/受保护的,因此无法访问。但我想知道第一个问题的答案。任何输入将不胜感激。

4

3 回答 3

6

访问控制是在编译时实现的,而不是在运行时实现的,而多态性(包括使用虚函数)是一种运行时特性。

于 2012-11-29T04:54:59.753 回答
6

在第一种情况下,访问检查是在调用所通过的静态类型上完成的(因为它总是这样做的)。的静态类型*bbase,在这种情况下doSomething()public

C++03 11.6 “访问虚函数” 说:

虚函数的访问规则(第 11 条)由其声明决定,不受稍后覆盖它的函数规则的影响。[例子:

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
}

——结束示例]

在调用点使用用于表示为其调用成员函数的对象的表达式类型(上例中的 B*)检查访问。成员函数在定义它的类中的访问(上例中的 D)通常是未知的。

特别要记住,“成员函数在定义它的类中的访问(上例中的 D)通常是未知的”。通常,在您的示例中b->doSomething();调用的位置,编译器可能根本不知道derived(or child),更不用说访问是否derived::doSomething()是私有的。

于 2012-11-29T04:57:13.777 回答
0

私有函数意味着对外部世界和派生类隐藏。尽管您覆盖了父 DoSomething 的访问说明符并将其设为私有,但您正在实例化一个基类;所以在第一种情况下,您可以调用 base 的 DoSomething,因为它是公开的。如果您想阻止人们从您的派生类派生,则可以使用此方案。

在第二种情况下,private访问说明符使基类的成员不暴露给派生类的用户,这实际上使派生类变得无用。

于 2012-11-29T05:12:05.170 回答