基类中的方法返回派生类类型?

问题描述 投票:6回答:3

我有一堆具有一个共同功能的类,除了它返回一个指向其自身类型的指针。代码看起来相同,我想将其移到抽象基类中。但是,如何使从其继承的类返回自己的类型?

class base {
    base *foo() {
        // ...
    }
};


class derived : public base {

};

derived d;
d.foo(); // Should return derived* instead of base*

有没有一种方法可以用C ++表示?

c++ inheritance c++11 return-type generic-programming
3个回答
11
投票

是的,C ++支持这一点。它称为协变量返回类型。您只需要声明虚拟函数并相应地声明返回类型。这就是全部。

struct base {
    virtual base *foo() {
        // ...
    }
};


struct derived : public base {
    virtual derived *foo() {
        // ...
    }
};

derived d;
base *base_ptr = d.foo();

现在您的评论扩展了原始问题:

但是实际上,我的目标是不重复函数体,因为它是除使用的类型外,其余相同。

这不可能。

[有多种技术可以促进重复,但是您不会回避这样一个事实,无论您做什么,仍然必须自己创建函数体。

一种这样的技术将使用宏,但代价是[[混淆以及宏附带的所有其他缺点;但是宏仍然不会自动出现在类中。您必须把它放在那里。

// beware of macros! #define FOO(T) virtual T *foo() { return new T; } struct base { FOO(base) virtual ~base() {} // let's not forget the virtual destructor }; struct derived : public base { FOO(derived) };
类似的方法是使用

template

来促进功能体的重复:template <class T> T *ComplicatedFunctionReturningT() { T *t; // ... // ... // ... return t; } struct base { virtual base *foo() { return ComplicatedFunctionReturningT<base>(); } virtual ~base() {} // let's not forget the virtual destructor }; struct derived : public base { virtual derived *foo() { return ComplicatedFunctionReturningT<derived>(); } };
模板比宏更安全。


另一种方法是使用模板方法设计模式。如果每个类的函数体中都重复了很多代码,请尝试在基类中尽可能多地移动,并将小的抽象部分放入要重写的私有函数中:

class base { public: base *foo() { // no longer virtual // ... // ... base *ptr = fooImpl(); // ... // ... return ptr; } virtual ~base() {} // let's not forget the virtual destructor private: virtual base *fooImpl() = 0; // pure virtual and private }; class derived1 : public base { private: virtual derived1 *fooImpl() { return new derived1; // very simple body } }; class derived2 : public base { private: virtual derived2 *fooImpl() { return new derived2; // very simple body } };


当然,只有在功能体非常复杂的情况下,所有这些才真正值得。在极端情况下,一种完全不同的方法是

使用某些外部工具或脚本生成C ++代码

最后,如果确实存在问题,请重新考虑整个设计。也许事实证明您确实不需要此功能,或者对于程序尝试解决的实际问题也不需要OOP。

3
投票
基于对基督徒答案的评论,您可以实现模板帮助器方法,以不重复使用的代码:

class base { protected: template<class T> T* fooInternal() { T* t = new T(); // do stuff with t return t; } public: virtual base* foo() { return fooInternal<base>(); } }; class derived : public base { public: virtual derived* foo() { return fooInternal<derived>(); } };


0
投票
[一种选择是使用CRTP(奇怪地重复使用模板模式)。

template<typename Derived> struct base { Derived* foo() { // ... return static_cast<Derived*>(this); } }; struct derived : base<derived> { // ... }; derived d; derived *derived_ptr = d.foo();

主要好处是您不需要宏或虚拟方法即可获得您关心的类型。

如果您在基类中使用多个方法来执行此操作,最好定义一个辅助方法。

template<typename Derived> struct base { Derived* foo() { // ... return self(); } private: Derived* self() { return static_cast<Derived*>(this); } };

例如,我已将这种模式用于属性对象,这些属性对象具有一组共享属性和一些具有其自身属性的派生属性对象。然后,我让基类方法返回对派生类的引用,以便可以在同一条语句上链设置多个属性。

SomePropertyObject() .setBaseProperty("foo") .setDerivedProperty("bar");

© www.soinside.com 2019 - 2024. All rights reserved.