我对多重继承问题感到有些困惑"。考虑以下大量代码:
#include <iostream>
struct iface
{
virtual void foo () = 0;
virtual ~iface () {}
};
struct wrapped
{
virtual void foo ()
{
std::cerr << "wrapped\n";
}
};
struct impl : public wrapped, public iface
{
};
iface* factory ()
{
return new impl;
}
int main ()
{
iface *object = factory ();
object->foo();
delete object;
return 0;
}
这是从使用pimpl习语的一些代码中抽象出来的。这个想法是wrapped
是一个复杂的类,有各种各样的花里胡哨。 iface
仅使wrapped
的特定方面可见,factory()
函数构建impl
类,使用iface
实现wrapped
。在我的真实代码中,wrapped
类来自具有巨大标题树的库,因此我在单独的编译单元中定义impl
以避免我的应用程序的其余部分必须将它们拉入。< / p>
无论如何,我粘贴的内容无法编译,并给出以下错误:
$ g++ -o test test.cc
test.cc: In function ‘iface* factory()’:
test.cc:23:16: error: cannot allocate an object of abstract type ‘impl’
return new impl;
^
test.cc:17:8: note: because the following virtual functions are pure within ‘impl’:
struct impl : public wrapped, public iface
^
test.cc:5:18: note: virtual void iface::foo()
virtual void foo () = 0;
^
显然,我可以通过在foo
中编写一个转发到impl
的{{1}}的具体实现来避免错误,但我不明白为什么编译器没有&#39} ; t从wrapped::foo()
类中获取实现。
我认为不知怎的&#34; foo&#34;来自wrapped
和&#34; foo&#34;来自iface
的{{1}}在为wrapped
进行名称解析(这是正确的词)时最终会有所不同,但我并不理解为什么。
有人能解释一下发生了什么吗?
答案 0 :(得分:3)
如果一个类的任何虚函数是纯虚函数,则该类是absrtract。 类impl有两个具有相同名称的成员函数
iface::foo
和
wrapped::foo
类impl的第一个成员函数是纯虚函数,因此该类是抽象的。编译器可能无法创建抽象类的对象。
答案 1 :(得分:1)
impl
有两个完全独立的方法,iface::foo
,纯粹的,wrapped::foo
。没有名称解析 - 虚拟函数调用由名为vtable的结构调度,该结构包含指向实现的指针。对于每个直接祖先,类都有单独的vtable,至少在没有虚拟继承的情况下。来自不同祖先的同义虚函数最终会出现在不同的vtable中;编译器无法“组合”它们。 C ++没有mixins。
显然,我可以通过在impl中编写foo的具体实现来避免错误,该实现转发到wrapped :: foo()
更好的是,不要使用双重继承 - 执行类似
的操作struct impl : public iface
{
virtual void foo ()
{
wr.foo ();
}
private:
wrapped wr;
};