在派生类中更改功能访问模式

时间:2010-01-26 17:20:18

标签: c++ inheritance access-modifiers

请考虑以下代码段:

struct Base
{
  virtual ~Base() {}

  virtual void Foo() const = 0; // Public
};

class Child : public Base
{
  virtual void Foo() const {} // Private
};

int main()
{
  Child child;

  child.Foo(); // Won't work. Foo is private in this context.

  static_cast<Base&> (child).Foo(); // Okay. Foo is public in this context.
}

这是合法的C ++吗? “这”正在改变派生类中虚函数的访问模式。

4 个答案:

答案 0 :(得分:21)

这是合法的C ++,§11.6/ 1说:

  

在呼叫点检查访问权限   使用所用表达式的类型   表示对象   调用成员函数(B *中的   上面的例子)。访问的   类中的成员函数   它已定义(示例中为D)   通常不知道。

正如您所指出的那样,Child::Foo()仍然可以通过基类访问,这在大多数情况下都是不受欢迎的:

 Child* c = new Child;
 Base* b = c;
 c->Foo(); // doesn't work, Child::Foo() is private
 b->Foo(); // works, calls Child::Foo()

基本上,你在表达式中引用的声明指示了访问模式 - 但是虚函数破坏了作为另一个函数的函数,然后实际上可以调用命名函数。

答案 1 :(得分:15)

是的,更改派生类中的访问模式是合法的。

类似表单,但不同意图使用Non-Virtual Interface成语。一些基本原理给出了here

  

重点是存在虚拟功能以允许定制;除非它们还需要直接从派生类的代码中调用,否则不需要将它们变成私有的。

至于为什么你实际上会在public基础上创建privateprivate在没有protected或{{1}}的情况下继承而已超出我的范围。

答案 2 :(得分:5)

这是完全合法的C ++。您只是在Child类中定义一个新方法。

现在它做了你想做的事,这是另一个问题。 我认为访问模式不是方法签名的一部分,这意味着调用Base的Foo虚方法最终会调用Child的Foo方法。

所以这里的结论是:它是合法的c ++,它的工作方式与你期望的一样。

我没有考虑行child.Foo();无法正常工作,因为毫无疑问它正在尝试访问Child的私有Foo()方法。

答案 3 :(得分:4)

似乎编译并调用正确的方法。

请记住,访问说明符可以帮助纪律严明的程序员,而不是阻止所有尝试不惜一切代价绕过它。

在这种特殊情况下,Child没有业务将被覆盖的虚拟函数设为私有:它是不是应该实现Base的公共接口,所以“is-a”关系成立? (如果你没有使用公共继承,这意味着“孩子是一个基础”,你的伎俩将不起作用。)