要求"公共"在自动范围中使用实例时的访问修饰符

时间:2016-06-17 10:41:24

标签: c++

假设我们有两个类,一个派生自另一个类,它只包含一个虚拟的非纯方法,如下所示:

class Base
{
public:
    virtual void method()
    {
        cout << "method() called from Base" << endl;
    }
};


class Derived : public Base
{
public:
    void method()
    {
        cout << "method() called from Derived" << endl;
    }
};


int main()
{
    Base *instance1 = new Derived();
    instance1->method();

    Derived derived;
    derived.method();
}

为什么,如果我们没有明确指定&#34; public&#34; Derived类中的访问修饰符(因此,编译器假定它是私有的)它不会编译?为什么实例化方式(通过指针和通过常规变量)确实会影响可见性范围?关于这种行为有什么理由吗?

非常感谢!

2 个答案:

答案 0 :(得分:1)

如果您不写public:,那么就好像您已经写过private:一样。如果你问为什么语言没有自动切换到public: Derived::method()(因为它会覆盖已经公开的Base::method())......好吧,它可以!这是可能的。

然而,在阅读代码时,它也会非常混乱和误导。作为一名程序员,我更喜欢我的课程定义并没有像我那样从根本上改变。

编译器抛出一个错误(正如您已经发现的那样),允许我在我认为合适的情况下自行进行更改(无论是Derived::method()公开还是Base::method()私人!),在我看来是迄今为止最好的结果。

相反,如果您不知道为什么可见度的差异甚至根本不重要,那么这似乎相当明显,不是吗?如果用户通过Base类接口调用函数,其中method()是公共的,并且最终自动调用派生类中的private函数,则违反了派生类。并且因为它只是受这些可见性规则保护的名称,所以该语言为重写方法添加了额外的检查,以便在虚函数调度的情况下尽可能地扩展该保护。

答案 1 :(得分:1)

在标准中给出了非常类似的东西,其中指定了这些东西的规则[class.access.virt]:

  

1确定虚拟功能的访问规则(第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 
}
     

- 结束示例]

     

2访问是   使用所用表达式的类型在调用点进行检查   表示调用成员函数的对象(B *中的   上面的例子)。成员函数在类中的访问权限   它的定义(上例中的D)通常是未知的。

以上回答了你的问题:

  1. 为什么不编译 - 按照上面的规则2,使用表达式的类型(即静态非动态类型)检查访问权限
  2. 理由是什么 - 再次如上所述,通常不知道动态类型是什么。为了演示,请考虑这一点:您可以将新派生类链接到定义基类的现有代码,而无需重新编译此代码:那么显然它没有机会确定派生的访问控制(当它是时它甚至不存在)编译)。