我想创建一个带有成员函数的类,该成员函数引用另一个类,其中两个类都是从抽象类派生的。我得到一个编译器错误,类Container是抽象的,因为它没有实现addElem()。
class Ielem
{
public:
virtual void action() = 0;
};
class Elem: public Ielem
{
public:
void action() {};
void extra() {};
};
class Icontainer
{
public:
virtual void addElem(Ielem &elem) = 0;
};
class Container: public Icontainer
{
public:
void addElem(Elem &elem) { elem.extra(); };
};
int main(int argc, char* argv[])
{
Elem e;
Container c;
c.addElem(e);
return 0;
}
这似乎应该有效,因为任何对Elem的引用也是对Ielem的引用。如果我使Container :: addElem引用Ielem,它会编译。但是然后Container :: addElem()不能调用Elem :: extra(),除非我使用的是在我正在使用的嵌入式编译器上不可用的dynamic_cast,或者是非类型安全的常规强制转换。 / p>
建议?
答案 0 :(得分:1)
这是错误的方法:基类Icontainer
指定addElem
可以将任何 Ielem
对象作为参数,但在您的派生类中仅接受 Elem
。这是一个“较窄”的类型,因此违反了我在基类中指定的“我将接受你向我抛出的任何Ielem
”的合同。
我认为模板将是解决方案。你甚至不再需要基类了。像这样:
class Elem
{
public:
void action() {};
void extra() {};
};
template<typename ElemType>
class Container
{
public:
void addElem(ElemType &elem) { elem.extra(); };
};
int main(int argc, char* argv[])
{
Elem e;
Container<Elem> c;
c.addElem(e);
return 0;
}
作为奖励,您现在可以将Container
与任何具有extra()
功能的类型一起使用,它就可以正常使用。
答案 1 :(得分:0)
问题很简单,你的虚方法与具有重载方法的具体方法没有相同的签名;因此,编译器完全将其视为一个不同的函数并抱怨,因为您尚未实现void addElem(Ielem &elem)
。这是一个你可能不想要的解决方案 -
class Icontainer
{
public:
virtual void addElem(Elem &elem) = 0; //Ielem -> Elem
};
这取决于你所有的其他限制因素,但我认为我会做什么 - 以及似乎符合一般设计指南,例如Sutter&amp; Alexandreascu,将使用完整的界面创建一个中间抽象类 -
class Melem: public Ielem
{
public:
// void action() {}; //Already have this form Ielem
void extra() = 0;
};
然后
class Icontainer
{
public:
virtual void addElem(Melem &elem) = 0;
};
class Container: public Icontainer
{
public:
void addElem(Melem &elem) { elem.extra(); };
//*Now* we're implementing Icontainer::addElem
};