c ++抽象类采用派生类参数

时间:2012-10-03 19:05:36

标签: c++ polymorphism abstract-class

我想创建一个带有成员函数的类,该成员函数引用另一个类,其中两个类都是从抽象类派生的。我得到一个编译器错误,类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>

建议?

2 个答案:

答案 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
};