在代码库中浏览我发现了以下内容:
class Interface{
public:
virtual void func() = 0;
};
class Implementation : public Interface{
protected:
void func() override {};
};
我认为这可能是编译错误,但似乎不是。它有什么意义?
答案 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();
}