问题描述
我曾经这样编写接口类:
class SomeInterface
{
public:
virtual void doThings() = 0;
virtual void run() = 0;
};
class OtherInterface
{
public:
virtual void doStuff() = 0;
virtual void run() = 0;
};
这意味着我可以轻松地继承多个接口并像这样使用它
class ConcreteClass : public SomeInterface,public OtherInterface
{
public:
virtual void doThings() { std::cout << "do things" << std::endl; }
virtual void doStuff() { std::cout << "do stuff" << std::endl; }
virtual void run() { std::cout << "do run" << std::endl; }
};
int main()
{
ConcreteClass myObject;
myObject.run();
return 0;
}
但是我最近阅读了有关非虚拟接口习惯用法(类似http://www.gotw.ca/publications/mill18.htm的东西)的信息,按照这些准则,我应该这样编写我的接口:
class SomeInterface
{
public:
void doThings() { doThingsImplementation(); }
void run() { runImplementation(); }
private:
virtual void doThingsImplementation() = 0;
virtual void runImplementation() = 0;
};
class OtherInterface
{
public:
void doStuff() { doStuffImplementation(); }
void run() { runImplementation(); }
private:
virtual void doStuffImplementation() = 0;
virtual void runImplementation() = 0;
};
这意味着其余代码现在看起来像这样
class ConcreteClass : public SomeInterface,public OtherInterface
{
private:
virtual void doThingsImplementation() { cout << "do things" << endl; }
virtual void doStuffImplementation() { cout << "do stuff" << endl; }
virtual void runImplementation() { cout << "run" << endl; }
};
int main()
{
ConcreteClass myObject;
myObject.run();
return 0;
}
...除了现在无法编译是因为对run()
的调用变得模棱两可(error: request for member ‘run’ is ambiguous
)。以前在界面上无害的重叠现在会导致名称冲突。
重新读取非虚拟接口惯用法的参数后,我感觉到问题是因为我将其应用于纯虚拟函数的虚拟函数。是吗我应该只将NVI习语用于非纯虚函数吗?
编辑1:有人指出run()
函数可以在其自己的接口类中。这实际上很有意义:要么两个run()
都具有相同的含义并且应该对接口进行分解,要么它们具有不同的含义,并且我们希望编译器将其说成是模棱两可的。在使用纯虚拟函数所不具备的NVI时,这仍然给我们带来了钻石继承问题
编辑2:事实证明,如果我将run()
作为其自己的接口类中的纯虚函数,SomeInterface
和{{1} }继承,事情实际上并不像我想的那样好。如果我引入了OtherInterface
(继承自两个接口类)并继承了CombinedInterface
,则可以在ConcreteClass
上调用run()
,但不能从{{ 1}}(同样,通话被认为是模棱两可的。)
结论:我在这里的要点是:1)接口不应重叠或不被考虑在内。和2)接口类之间的继承应该始终是虚拟的
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)