只是一个小烦恼,因为我可以通过包装派生函数而不是使用“using”关键字来解决问题,但为什么以下不起作用(编译器告诉我“get_elem”在“Bar”中仍然是纯虚拟的)班级)。
class Elem {};
class DerivedElem : public Elem {};
class Foo {
public:
virtual Elem& get_elem() = 0;
};
class Goo {
protected:
DerivedElem elem;
public:
DerivedElem& get_elem() { return elem; }
};
class Bar : public Foo, public Goo {
public:
using Goo::get_elem;
};
int main(void) {
Bar bar;
}
Cheers,
Tom
如果 Goo 是一个“mixin”,旨在以特定方式实现 Foo 接口(可能还有其他具有其他实现的 mixin),那么 Goo 可以从 Foo 派生(而不是 Bar 这样做)。
如果 Goo 不是为了实现 Foo 接口而设计的,那么将 Bar 视为已经实现了纯虚函数将是一个可怕的错误,而事实上它只是碰巧具有相同签名的函数。如果您想要隐式接口和 C++ 中的“鸭子”类型,您可以做到这一点,但您必须使用模板来做到这一点。不管正确与否,纯虚函数适用于显式声明的接口,而 Goo 的get_elem
函数未显式声明要实现Foo::get_elem
。所以事实并非如此。
我想这并不能解释为什么原则上该语言无法定义using Goo::get_elem for Foo;
,或 Bar 中的一些此类声明,以避免 Bar 需要包含大量包装调用的样板文件。
你也许可以用模板做一些事情来允许Goo
在某种程度上支持这一点,而不真正了解 Foo:
template <typename T>
class Goo : public T {
protected:
DerivedElem elem;
public:
DerivedElem& get_elem() { return elem; }
};
class Bar : public Goo<Foo> {};
class Baz : public Goo<Fuu> {};
其中 Fuu 是其他一些具有get_elem
功能。显然这是作者的责任Bar
为了保证Goo
确实履行了合同Foo
,同样对于Baz
检查合同Fuu
.
顺便说一句,这种形式的协方差有点狡猾。看着 Foo,有人可能会想到这样的表情bar.get_elem() = Elem()
是有效的,但它不是,所以违反了 LSP。参考文献就是这样有趣。((Foo &)bar).get_elem() = Elem()
有效,但一般不起作用!它仅分配给Elem
子对象,就此而言也是如此((Foo &)bar).get_elem() = DerivedElem()
。多态赋值基本上是一个麻烦。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)