虚函数返回类型

时间:2013-04-07 18:59:05

标签: c++ override covariant

我在基类中定义了纯虚函数 虚拟int GetData() const = 0;

在每个派生类中,我定义了一个枚举并尝试重写GetData函数返回 (派生类特定枚举)值;

例如:

class Derived1 : public Base
{
public :
enum D1
{
   d1_1 = 0,
   d1_2 = 60,
   ...
   d1_100
};
D1 GetData () const;
};
class Derived2 : public Base
{
public :
enum D2
{
   d2_1 = 10,
   d2_2 = 39,
   ...
   d2_300
};
D2 GetData () const;
};

非常重要的是,我可以为所有类别的所有enum valuyes定义相同的范围。 上面的代码生成编译错误:

error C2555: : overriding virtual function return type differs and is not covariant

任何建议 - 如何解决?

4 个答案:

答案 0 :(得分:2)

在您的特定情况下,您的virtual方法返回一个基本类型,它没有协方差,因为它无法放入C#中的System.Object这样的公共类型。
您需要定义一个类作为所有返回类型的基类,以便完全填充协方差。

来自维基百科:

Within the type system of a programming language, covariance and contravariance refers to the
ordering of types from narrower to wider and their interchangeability or equivalence in certain 
situations (such as parameters, generics, and return types).

covariant: converting from a specialized type (Cats) to a more general type (Animals): 
Every cat is an animal.

Here是该文章的链接。

答案 1 :(得分:1)

只有在使用指向派生类的指针/引用替换指向基类的指针/引用时,才允许更改虚函数的返回类型,因为可以安全地将其转换为另一个。虽然枚举类型与int兼容,但它们在技术上并不相关。只需在任何地方使用int,因为枚举名称只是一种装饰,并且根本不会影响任何内容。

答案 2 :(得分:1)

您的设计需要修复,但仅关于技术,您可以

class Derived1
    : public Base
{
public:
    enum D1
    {
       d1_1 = 0,
       d1_2 = 60,
       ...
       d1_100
    };
    D1 GetD1Data () const;
    int GetData() const override { return GetD1Data(); }
};

答案 3 :(得分:1)

根据C ++ 11 ISO 10.3 / 7:

  

重写函数的返回类型要么与被覆盖函数的返回类型相同,要么协变与函数类相同。如果函数D :: f覆盖函数B :: f,那么函数的返回类型如果满足以下条件则是协变的

     

- 都是指向类的指针,都是对类的左值引用,或者两者都是对类的右值引用

     

- 返回类型B :: f中的类与返回类型为D :: f的类相同,或者是返回类型中类的明确且可访问的直接或间接基类D :: f

     

- 指针或引用都具有相同的cv限定,并且返回类型D :: f中的类类型与返回类型B中的类类型具有相同的cv-qualification或更少的cv-qualification: :˚F

仅允许指针,左值/右值引用的协方差。我想你不想通过引用或指针返回枚举。

但是,如果您接受静态线程本地缓冲区,则可以使用以下方法:

LIVE DEMO

class EnumA
{
    int value_;
public:
    explicit EnumA(int v)
        : value_{v}
    {}
    int value() const
    {
        return value_;
    }
};
struct EnumB: EnumA
{
    enum EnumB_T{one,two};
    explicit EnumB(EnumB_T v)
        : EnumA{v}
    {}
    EnumB_T value() const
    {
        return EnumB_T(EnumA::value());
    }
};

struct A
{
    virtual const EnumA &func() const
    {
        static thread_local EnumA result{0};
        return result = EnumA{1};
    }
};

struct B: A
{
    virtual const EnumB &func() const override
    {
        static thread_local EnumB result{EnumB::one};
        return result = EnumB{EnumB::two};
    }
};