C++ 为什么可以更改虚拟成员或公共基类的可见性?

C++ 为什么可以更改虚拟成员或公共基类的可见性?,c++,oop,C++,Oop,浏览代码库时,我在以下行中发现了一些内容: class Interface{ public: virtual void func() = 0; }; class Implementation : public Interface{ protected: void func() override {}; }; 我原以为这是一个编译错误,但似乎不是。这有什么意义 这有什么意义 是的,这是有道理的。如果尝试创建派生类型的对象,将无法调用该方法。因此,我们的想法是始终

浏览代码库时,我在以下行中发现了一些内容:

class Interface{
    public:
    virtual void func() = 0;
};

class Implementation : public Interface{
    protected:
    void func() override {};
};
我原以为这是一个编译错误,但似乎不是。这有什么意义

这有什么意义

是的,这是有道理的。如果尝试创建派生类型的对象,将无法调用该方法。因此,我们的想法是始终通过对象的接口访问对象

这样做的目的是为了实施这一政策


#包括
#包括
#包括
结构基
{
公众:
虚拟~Base(){}
虚拟void foo()=0;
};
结构Derived1:Base
{
受保护的:
虚拟void foo(){

std::coutFreedom。有时它可能有点有用(例如,如果您想隐藏一个您不希望使用的成员),至少当他们通过派生类访问时是这样

将其视为一种“显式实现”。例如,您有一个这样的基本接口
List
(非常简化的代码用于说明):

您创建了实现
List
接口的
ReadOnlyList
具体类,在这种情况下,您不鼓励类的用户调用
add()
方法,只需更改其可见性即可。除非他们通过
List
接口访问它,否则它将被隐藏

另一个例子?如果您想为某些特定任务提供一个接口,但它是一个实现细节,不是类契约的一部分。在这种情况下,您将它们设置为受保护的或私有的,并且它们将不可访问

也就是说,它是如此的脆弱和混乱,除了极少数有注释且控制良好的异常之外,我将避免这样做。

在C++中:

  • 可访问性是一个“静态”概念(在编译时检查),而
  • 虚拟分派是一个“动态”概念(要调用的实现是在运行时选择的)
<>我们可以说C++保持了这两个概念“正交”。 因此,对于您的示例,这将编译(不是真实的代码,只是示例):

但这不会:

Implementation obj;
obj.func(); // error: Implementation::func is protected

有效地“强制”您只使用接口(这可能是您的意图)。-编辑:请参阅,以获得更好的设计。

Freedom。有时它可能有点有用(例如,如果您想隐藏一个您不希望使用的成员)。至少当他们通过派生类访问时是这样。将其视为一种“显式实现”。也就是说,它是如此脆弱和混乱,我会毫无例外地避免它。我认为从私有到公共比从私有到公共更有意义。@原因很简单?从私有到公共毫无意义。@Bааћ如果您有私有成员函数,那么您可能希望将其作为接口的一部分公开,因此您将其公开。我发现比从public->private更明智,在那里你可以使用cast来绕过它。@在这种情况下,很简单,你不能使用基类作为对象的接口。你总是必须从case到derived,这很糟糕。更好的设计是不允许虚拟函数的可见性被改变。@PaulManta One可能会争论这个问题,但不管怎样,我指的是“编程设计”(程序员),而你指的是“语言设计”(Bjarne Stroustrup和/或ISO C++委员会)。
class List {
public:
    virtual void add(std::string item) = 0;
    virtual std::string at(int index) = 0;
};
Implementation obj;
Interface& ref = obj;
ref.func(); // (will call obj.func())
Implementation obj;
obj.func(); // error: Implementation::func is protected