我在尝试重用不同类的代码时偶然发现了一个问题。我在这里发帖,希望你们中的一些人能够帮助我。
我有一组派生自同一个类(A)的类(B,C),这些类强制执行某些方法(foo,run)。 B类实现了这些方法,B和C都提供了其他方法:
#include<iostream>
template<class I, class O>
class A {
public:
A() {}
virtual ~A() {}
virtual void foo() const = 0; // force implementation of this function
virtual void run() const = 0; // force implementation of this function
};
template<class I, class O>
class B : public A<I,O> {
public:
B() {}
virtual ~B() {}
virtual void foo() const { // implementation for the Base class
std::cout << "B's implementation of foo" << std::endl;
}
virtual void run() const { // implementation for the Base class
std::cout << "B's implementation of run" << std::endl;
}
virtual void foobar() const { // some other function provided by this class
std::cout << "B's implementation of foobar" << std::endl;
}
};
template<class I, class O, class M>
class C : public A<I,O> {
public:
C() {}
virtual ~C() {}
virtual void bar(M m) const { // some other function provided by this class
std::cout << "C's implementation of bar with: " << m << std::endl;
}
};
现在,我要做的是从B和C继承,以便我可以拥有额外的方法(foobar,bar),但也不必从A类(foo)实现该方法,因为它已经是在B中定义:
template<class I, class O>
class D : public B<I,O>, public C<I,O,int> {
public:
D() {}
void run() const {
this->bar(123);
this->foo();
this->foobar();
}
};
但由于某种原因,编译器给了我这个错误:
test.cpp:在函数'int main(int,char **)'中: test.cpp:68:35:错误:无法分配抽象类型的对象'D&lt; float,double&gt;'
A&lt; float,double&gt; * d = new D&lt; float,double&gt;(); //我需要做什么
test.cpp:48:11:注意:因为以下虚函数在'D&lt; float,double&gt;'中是纯粹的:
D类:公共B&lt; I,O&gt;,公共C&lt; I,O,int&gt; {
^
test.cpp:9:22:注意:void A&lt; I,O&gt; :: foo()const [with I = float; O =双倍]
virtual void foo()const = 0; //强制执行此功能
这是我用来运行它的代码:
int main(int argc, char **argv)
{
A<float, double> *b = new B<float, double>();
b->foo(); // prints "B's implementation of foo"
b->run(); // prints "B's implementation of run"
//A<float, double> *c = new C<float, double, int>(); // obviously fails because C does not implement any of A's functions
//A<float, double> *d = new D<float, double>; // line 68: what I need to do
//d->run(); // ***throws the abstract class error
return 0;
}
我想从指向A的指针使用D类对象的'run'函数。由于所有函数都是虚函数,我希望执行在最低继承点中定义的每个函数的实现,这意味着'B :: run'将被丢弃。由于'D :: run'使用B和C中的函数,我需要继承这两个类。
我希望我已经足够描述并且没有让任何人感到困惑。 谢谢你的帮助!
答案 0 :(得分:6)
如果您将B
和C
更改为从A
模板类进行虚拟继承,那么当它们由D
合并时,它们将共享一个基本实例,此错误将会发生程:
template<class I, class O>
class B : virtual public A<I,O> {
// ...
template<class I, class O, class M>
class C : virtual public A<I,O> {
然而,这种模式(称为钻石继承(反)模式)可能很难推理,我强烈建议尽可能避免使用它。你以后可能会遇到更加模糊的问题。
以下是此技术的一个示例,但显示了一些乍看之下可能无法预料到的结果:
class A {
public:
virtual void foo() = 0;
};
class B : virtual public A {
public:
virtual void foo() override;
};
void B::foo()
{
std::cout << "B::foo()" << std::endl;
}
class C : virtual public A { };
class D : public B, public C { };
int main() {
D d;
C & c = d;
c.foo();
return 0;
}
请注意,即使您正在调用C::foo()
,这是纯虚拟的,因为只有一个A
实例,继承的纯虚函数会解析为B::foo()
,但共享{{1} vtable。这是一个有点令人惊讶的副作用 - 您可以最终调用在表兄弟类型上实现的方法。
答案 1 :(得分:2)
@cdhowie的答案为您提供了解决方案。
要理解编译器抱怨的问题,请采用一组更简单的类:
struct A
{
virtual void foo() = 0;
};
struct B : A
{
virtual void foo() {}
}
struct C : A
{
void bar() {}
}
struct D : B, C
{
};
D
的类层次结构是:
A A
| |
B C
\ /
D
使用此继承结构,D
有两个虚拟表,一个对应于B
继承层次结构,另一个对应于C
继承层次结构。不同之处在于,B
层次结构中存在A::foo()
的实现,而C
层次结构中没有一个。
假设您被允许构造D
类型的对象。
D d;
C* cp = &d;
现在cp
指向C
的{{1}}层次结构,并使用未实现D
的虚拟表。这将是编译器在编译时帮助您避免的运行时错误。
答案 2 :(得分:0)
我知道这是一个迟到的答案,但由于你是从C类的纯虚函数派生出来的,你必须实现它,然后在那些函数中调用基类:
virtual void foo() const { // for class C
B::foo();
}