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

时间:2013-12-09 11:50:20

标签: c++ oop

在代码库中浏览我发现了以下内容:

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

class Implementation : public Interface{
    protected:
    void func() override {};
};

我认为这可能是编译错误,但似乎不是。它有什么意义?

3 个答案:

答案 0 :(得分:3)

在C ++中:

  • 辅助功能是一种“静态”概念(在编译时检查),而
  • 虚拟调度是一个“动态”概念(在运行时选择要调用的实现)。

我们可以说C ++将这两个概念保持为“正交”。

所以在你的例子中,这将编译(不现实的代码,只是插图):

Implementation obj;
Interface& ref = obj;
ref.func(); // (will call obj.func())

但这不会:

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

有效地“强迫”你只使用界面(可能是意图)。 - 编辑:请参阅Dieter Lücking's answer以获得更好的设计。

答案 1 :(得分:1)

自由。有时它可能有用(例如,如果你想隐藏你想要阻止使用的成员)。至少当他们通过派生类访问时。

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

class List {
public:
    virtual void add(std::string item) = 0;
    virtual std::string at(int index) = 0;
};

您创建实现ReadOnlyList界面的List具体类,在这种情况下,您会阻止您的班级用户调用add()方法,只需更改其可见性。除非他们通过List界面访问它,否则它将被隐藏。

另一个例子?如果您想为某些特定任务提供界面,但它是一个实现细节,而且不属于类合同。在这种情况下,您可以将它们设为受保护或私有,并且无法访问它们。

那说它太弱而且令人困惑,除了极少数,评论和控制良好的例外之外,我会避免这样做。

答案 2 :(得分:0)

  

它有什么意义?

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

我们的想法是强制执行Interface segregation principle


#include <iostream>
#include <vector>
#include <memory>

struct Base
{
public:
    virtual ~Base(){}

    virtual void foo() = 0;
};

struct Derived1 : Base
{
protected:
    virtual void foo(){
        std::cout << "foo 1" << std::endl;
    }
};
struct Derived2 : Base
{
protected:
    virtual void foo(){
        std::cout << "foo 2" << std::endl;
    }
};


void wouldFail()
{
    Derived1 d;


    // d.foo(); -- Error! Do not try to call it directly
}

void ok()
{
    std::vector< std::shared_ptr< Base > > v;

    v.emplace_back( std::make_shared<Derived1>() );
    v.emplace_back( std::make_shared<Derived2>() );

    for ( auto & it : v )
        it->foo();
}

int main()
{
    wouldFail();
    ok();
}