3

我想为从基类派生的所有类强制使用某个 API。通常,您可以使用具有纯虚函数的抽象基类来执行此操作。但是,如何处理返回派生类型的函数?我该如何去强制这种类型的功能?

struct base
{
    virtual base func() = 0;
};

struct deriv1 : base
{
    deriv1 func();
};

struct deriv2 : base
{
    deriv2 func();
};

此示例将给出类似“成员函数的无效抽象返回类型”的错误。我已经看到一些建议返回指针的答案,但我不想为此深入研究动态内存,并且跟踪所有分配的指针将是一种特殊的地狱。有任何想法吗?

4

3 回答 3

2

当虚函数返回一个类的指针或引用时,允许从基类继承并覆盖该函数的类将返回类型更改为从原始返回类型派生的类的指针或引用。

您不能按值返回 base,因为它是抽象的,因此您实际上不能自己创建一个。

http://en.wikipedia.org/wiki/Covariant_return_type

使用虚函数和基类时,通常必须使用动态分配来创建对象。我建议您研究智能指针以帮助管理内存。

于 2013-08-01T20:19:03.783 回答
1

在您的示例中, thefunc不会是“相同的功能”,因此deriv1andderiv2变体不会具有不同的虚功能。

不幸的是,除了返回指针之外别无选择 - 它不必是指向动态分配内存的指针(例如,您可以返回指向this或 a的指针static deriv2 anObject;- 但它必须是指向 的指针base。[或 a参考,但同样的问题适用]。

造成这种情况的主要原因(除了“函数不能仅在返回类型上进行区分”这一事实之外)是,如果你有一些看起来像这样的通用代码:

vector<base*> v;
... stuff a bunch of `dervi1` or `deriv2` objects into v. 
for(i : v)
{
    base b = i->func();
}

现在,要么你现在已经将你的deriv1deriv2切割成 a 的大小,要么你已经复制了一个base大于-size 对象的对象——这两者都没有任何好处。[我假设在真正的用例中,实际上与对象名称的不同之处在于更多方面 - 否则,这是毫无意义的。那当然是继承自]。basebasederiv1deriv2basederiv1deriv2base

换句话说,您不能使用 复制未知类型的对象=。如果你必须知道它返回什么类型,那么拥有一个虚函数绝对没有意义。

于 2013-08-01T20:30:38.240 回答
0

基本上是说“如果你想在你的代码中用 deriv2 替换 deriv1,你需要实现这些函数”

从您上面的报价来看,您似乎想要这样的东西:

#include <memory> //for unique_ptr
#include <iostream>

struct Base
{
  virtual void doX() = 0;
  virtual void doY() = 0;
  virtual ~Base(){}
};

struct D1 : Base
{
  virtual void doX()
  {
    std::cout << "D1::doX()" << std::endl;  
  }
  virtual void doY()
  {
    std::cout << "D1::doY()" << std::endl;  
  }
};

struct D2 : D1
{
  virtual void doX()
  {
    std::cout << "D2::doX()" << std::endl;  
  }
  virtual void doY()
  {
    std::cout << "D2::doY()" << std::endl;  
  }
};

//From this point on you can do various things:

void driver()
{
  Base* base = new D1;//
  base->doX(); //Calls D1::doX()
  D1* d1 = new D2;
  d1->doX(); //Calls D2::doX()
}
// or...
void driver( Base* base )
{
  //A way to replace Base with D1 with D2 depending
  // on how driver was called.
}

//Finally, maybe you want a factory to create the correct
// derived type based on which factory was instantiated.

// Creates family of products, each item representing the base
// in it's hierarchy - only one shown here...
struct AbstractFactory
{
  virtual std::unique_ptr<Base> create() const = 0;
  protected:
    virtual ~AbstractFactory(){}
};

struct D1Factory : AbstractFactory
{
  //Doesn't matter if <Derived> is returned, because it adheres
  // to interface of Base (isA base), and correct functions are
  // found polymorphically 
  virtual std::unique_ptr<Base> create() const
  {
    return std::unique_ptr<Base>( new D1 ); 
  }
};
struct D2Factory : AbstractFactory
{
  //Doesn't matter if <Derived> is returned, because it adheres
  // to interface of Base (isA base), and correct functions are
  // found polymorphically 
  virtual std::unique_ptr<Base> create() const
  {
    return std::unique_ptr<Base>( new D2 ); 
  }
};

void driver( const AbstractFactory& factory )
{
  std::unique_ptr<Base> base( factory.create() );
  base->doX();
  base->doY();
  //Memory deallocated automagically...
}

int main()
{
  driver( D1Factory() );
  driver( D2Factory() );
}

你会看到这对你的报价是正确的。D2从驱动的角度无缝替代了D1...

于 2013-08-01T21:46:47.163 回答