我想为从基类派生的所有类强制使用某个API。通常,您使用具有纯虚函数的抽象基类来执行此操作。但是,如何处理返回派生类型的函数?我如何强制执行此类功能?
struct base
{
virtual base func() = 0;
};
struct deriv1 : base
{
deriv1 func();
};
struct deriv2 : base
{
deriv2 func();
};
此示例将给出类似“成员函数的无效抽象返回类型”之类的错误。我已经看到了一些建议返回指针的答案,但我并不特别想进入动态内存,并且跟踪所有已分配的指针将是一种特殊的地狱。有什么想法吗?
答案 0 :(得分:1)
当虚函数返回对类的指针或引用时,允许从基类继承并覆盖该函数的类将返回类型更改为指针或对从原始返回派生的类的引用类型。
由于它是抽象的,因此您无法按值返回,因此您实际上无法自行创建。
http://en.wikipedia.org/wiki/Covariant_return_type
使用虚函数和基类时,通常必须使用动态分配来创建对象。我建议你研究智能指针来帮助管理内存。
答案 1 :(得分:1)
在您的示例中,func
不会是“相同的功能”,因此deriv1
和deriv2
变体不会有不同的虚函数。
不幸的是,除了返回指针之外别无选择 - 它不必是指向动态分配内存的指针(例如,您可以返回指向this
或static deriv2 anObject;
的指针 - 但它必须是指向base
的指针。[或参考,但同样的问题适用]。
这个的主要原因(除了“函数不能仅仅在返回类型上区分”这一事实)是,如果你有一些看起来像这样的通用代码:
vector<base*> v;
... stuff a bunch of `dervi1` or `deriv2` objects into v.
for(i : v)
{
base b = i->func();
}
现在,您现在要么已将[{1}}或deriv1
[切成]切成deriv2
的大小,或者您已经复制了大于{的对象{1}}成为base
大小的对象 - 这些对象都不会带来任何好处。 [我假设在真实的用例中,base
和base
实际上与deriv1
的区别在于对象名称的更多方面 - 否则,它是相当的无意义。而deriv2
和base
当然是继承自deriv1
。
换句话说,您无法使用deriv2
复制未知类型的对象。如果您必须知道它返回的类型,那么拥有虚函数绝对没有意义。
答案 2 :(得分:0)
块引用
基本上是一种说法“如果你想在代码中用deri2替换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 从司机的角度无缝地......