覆盖函数(来自两个抽象基类),它们的区别仅在于它们的返回值

时间:2013-08-30 09:19:22

标签: c++ templates inheritance multiple-inheritance

我想创建一个实现两个接口的类,这些接口具有同名的函数,这些函数的返回值不同。我怎么能正确地做到这一点?

template<class T>
class IBase
{
public:
    virtual T Method() = 0;
};

class Derived : public IBase<int>, public IBase<char> {
public:
    int _value;

    virtual int IBase<int>::Method();
    virtual char IBase<char>::Method();
};

int Derived::Method() {
    return _value;
}

char Derived::Method() {
    return _value;
}

以下是我得到的错误:

error C2555: 'Derived::Method: overriding virtual function return type differs and is not covariant from 'IBase<int>::Method

error C2556: 'int Derived::Method(void)' : overloaded function differs only by return type from 'char Derived::Method(void)'

error C2371: 'Derived::Method: redefinition; different basic types

error C2084: function 'char Derived::Method(void)' already has a body

在C#中,使用几乎相同的语法(称为显式接口实现)可以很容易地做到这一点而没有任何歧义:

class Derived : IBase<int>, IBase<char> {
    int _value;

    int IBase<int>.Method() {
        return _value;
    }

    char IBase<char>.Method();
        return _value;
    }
};

显式实现是私有的,因此不能直接用于类Derived的变量。它们仍然非常有用,因为您可以将Derived强制转换为其中一个接口以使用该实现:

var d = new Derived();
((IBase<int>)d).Method();

这可能非常有用。一个类可以多次实现ICanConvertTo以启用不同的转换。

3 个答案:

答案 0 :(得分:3)

在Derived中使用虚拟

#include <iostream>

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

template<typename T>
class WrapBase : public IBase<T>
{
    protected:
    virtual T do_method(T*) = 0;

    public:
    virtual T method() {
        return do_method((T*)0);
    }
};

class Derived : public WrapBase<char>, public WrapBase<int>
{
    protected:
    virtual char do_method(char*) { return 'A'; };
    virtual int do_method(int*) { return 1; };
};

在Derived中删除虚拟 - 感谢DyP

include <iostream>

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

template<typename D, typename T>
class WrapBase : public IBase<T>
{
    public:
    virtual T method();
};

class Derived : public WrapBase<Derived, char>, public WrapBase<Derived, int>
{
    friend class WrapBase<Derived, char>;
    friend class WrapBase<Derived, int>;

    protected:
    char do_method(char*) { return 'A'; };
    int do_method(int*) { return 1; };
};

template<typename D, typename T>
inline T WrapBase<D, T>::method() {
    return static_cast<D*>(this)->do_method((T*)0);
}

测试:

int main () {
    Derived d;
    IBase<char>& c = d;
    IBase<int>& i = d;
    std::cout << c.method() << " != " << i.method() << std::endl;
}

评论:混合静态和动态多态可能是一个糟糕的设计。

答案 1 :(得分:2)

函数只能通过返回值区分,因为编译器无法区分它们。考虑:

long x;
Derived d;
x = d.Method();

charint变体都可以转换为long - 应该使用哪一个?

编辑: 如果要定义转换,典型的情况是定义一个转换运算符,例如

class X 
{
     float x;
   public:
     X(float f) : x(f) {}
     operator int() { return static_cast<int>(x); }
     operator char() { return static_cast<char>(x); }
     float getX() { return x; }
};

然后将其命名为:

X x(65.3);
int y = x;
char z = x;

cout << "x.f=" << x.getF() << " as char:" << z << " as int:" << y << endl;

答案 2 :(得分:1)

返回值类型不是函数(方法)签名的一部分。

因此,您的两种方法被视为相同的方法(因此重新定义错误)。

所以你不能做你想做的事。你的方法应该有不同的签名。