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

dan*_*jar 6 c++ inheritance return-type generic-programming c++11

我有一堆具有一个共同功能的类,除了它返回一个指向它们自己类型的指针.代码看起来一样,我想把它移到一个抽象的基类中.但是,我怎样才能使从它继承的类返回自己的类型?

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


class derived : public base {

};

derived d;
d.foo(); // Should return derived* instead of base*
Run Code Online (Sandbox Code Playgroud)

有没有办法用C++表达这个?

Chr*_*ckl 11

是的,C++支持这一点.它被称为协变返回类型.您只需要声明函数virtual并相应地声明返回类型.这里的所有都是它的.

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


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

derived d;
base *base_ptr = d.foo();
Run Code Online (Sandbox Code Playgroud)

现在你的评论扩展了原来的问题:

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

这是不可能的.

有各种各样的技术可以促进重复,但你不会解决这样一个事实,无论你做什么,你仍然必须自己创建功能体.

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

// 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)
};
Run Code Online (Sandbox Code Playgroud)

类似的方法是使用模板来促进函数体的重复:

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>();
    }
};
Run Code Online (Sandbox Code Playgroud)

模板比宏更安全.


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

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
    }
};
Run Code Online (Sandbox Code Playgroud)

当然,如果函数体非常复杂,所有这些都是值得的.对于极端情况,完全不同的方法是使用一些外部工具或脚本生成C++代码.

最后,如果这确实是个问题,请重新考虑整个设计.也许事实证明你并不真正需要这个功能,或者你不需要OOP来解决你的程序试图解决的实际问题.

  • @danijar:通过OOP的通常定义,单个虚函数的存在使您的类成为OOP类.但那是分裂的.软件工程领域几乎没有任何一个词像"OOP"那样过载和滥用:) (2认同)