在基类中返回抽象类型

时间:2011-10-28 00:36:15

标签: c++ oop inheritance abstract-class

在类层次结构的设计中,我使用的是一个抽象基类,它声明派生类将实现的各种方法。从某种意义上说,基类与C ++中的接口一样接近。但是,有一个具体问题。考虑下面的代码声明我们的接口类:

class Interface {
public:
    virtual Interface method() = 0;
};

class Implementation : public Interface {
public:
    virtual Implementation method() { /* ... */ }
};

当然,这不会编译,因为你不能在C ++中返回一个抽象类。为了解决这个问题,我使用以下解决方案:

template <class T>
class Interface {
public:
    virtual T method() = 0;
};

class Implementation : public Interface<Implementation> {
public:
    virtual Implementation method() { /* ... */ }
};

这个解决方案很有效,但对我来说,它看起来并不优雅,因为文本的冗余位是接口的参数。如果你们能用这个设计指出我们的任何其他技术问题,我会很高兴,但这是我唯一关注的问题。

有没有办法摆脱冗余模板参数?可能使用宏?

注意:有问题的方法必须返回一个实例。我知道如果method()返回指针或引用,则没有问题。

2 个答案:

答案 0 :(得分:5)

如果不使用指针或引用,

Interface::method()将无法返回Interface实例。返回非指针,非引用Interface实例需要实例化Interface本身的实例,这是非法的,因为Interface是抽象的。如果希望基类返回对象实例,则必须使用以下之一:

指针:

class Interface
{
public:
  virtual Interface* method() = 0;
};

class Implementation : public Interface
{
public:
  virtual Interface* method() { /* ... */ }
};

参考:

class Interface
{
public:
  virtual Interface& method() = 0;
};

class Implementation : public Interface
{
public:
  virtual Interface& method() { /* ... */ }
};

模板参数:

template<type T>
class Interface
{
public:
  virtual T method() = 0;
};

class Implementation : public Interface<Implementation>
{
public:
  virtual Implementation method() { /* ... */ }
};

答案 1 :(得分:5)

虽然由于显而易见的原因你无法通过 value 返回,但返回指针或引用完全没问题 - 这称为“协变返回类型”,它是一种有效的虚函数形式压倒一切的:

struct Base { virtual Base * foo(); }
struct Derived : Base { virtual Derived * foo(); }

关键是Derived::foo()是真正的覆盖,而不是基础隐藏重载,因为Derived*是指向派生类{{1}的指针}}。这同样适用于参考文献。

换句话说,如果你有一个Base,并且你致电Base * p,你可以随时将结果视为指向p->foo()的指针(但是如果您有其他信息,例如因为你的班级实际上是Base,那么你可以使用那些信息。)

相反的组合顺序,即“逆变参数类型”,不允许作为C ++的一部分。