2

我想用一个成员函数创建一个类,该函数引用另一个类,其中两个类都派生自抽象类。我收到一个编译器错误,指出类 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,这在我正在使用的嵌入式编译器上不可用,或者常规转换,它不是类型安全的。

建议?

4

2 回答 2

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()函数的类型一起使用,并且它可以正常工作。

于 2012-10-03T19:10:22.327 回答
0

问题只是您的虚拟方法与旨在重载它的具体方法没有相同的签名;所以编译器将它完全视为一个不同的函数并抱怨你没有实现void addElem(Ielem &elem). 这是一种您可能不想要的解决方案——

class Icontainer
{
public:
  virtual void addElem(Elem &elem) = 0;  //Ielem -> Elem
};

这取决于您的所有其他约束,但我认为我会做什么——以及似乎符合一般设计准则的做法,例如 Sutter 和 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
};
于 2012-10-03T20:34:49.963 回答