C++ 虚函数返回类型

C++ 虚函数返回类型,c++,overriding,covariant,C++,Overriding,Covariant,我在基类中有一个纯虚函数,定义为 虚拟int GetData const=0 在每个派生类中,我定义一个枚举并尝试重写GetData函数return 派生类特定的枚举值 例如: class Derived1 : public Base { public : enum D1 { d1_1 = 0, d1_2 = 60, ... d1_100 }; D1 GetData () const; }; class Derived2 : public Base { public :

我在基类中有一个纯虚函数,定义为 虚拟int GetData const=0

在每个派生类中,我定义一个枚举并尝试重写GetData函数return 派生类特定的枚举值

例如:

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;
};
很重要的一点是,我不能为所有类中的所有枚举值定义相同的范围。 上面的代码生成编译错误:

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

有什么建议吗?如何解决这个问题?

在您的特定情况下,您的虚方法返回一个基元类型,它没有协方差,因为它不能放在像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.

是文章的链接。

在您的特定情况下,事实是您的虚拟方法返回一个基元类型,它没有协方差,因为它不能放在像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.

是文章的链接。

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

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

您的设计需要固定,但只考虑您可以做的技术

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

你的设计需要修正,但考虑到你能做的技术

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

根据C++11 ISO 10.3/7:

重写函数的返回类型应与重写函数的返回类型相同,或与函数类共变。如果函数D::f重写函数B::f,则函数的返回类型是协变的,前提是它们满足以下条件:

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

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

-两个指针或引用都具有相同的cv限定,并且D::f的返回类型中的类类型具有与B::f的返回类型中的类类型相同的cv限定,或者小于B::f的返回类型中的类类型

协方差仅允许用于指针、左值/右值引用。我猜您不想通过引用或指针返回枚举

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


根据C++11 ISO 10.3/7:

重写函数的返回类型应与重写函数的返回类型相同,或与函数类共变。如果函数D::f重写函数B::f,则函数的返回类型是协变的,前提是它们满足以下条件:

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

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

-两个指针或引用都具有相同的cv限定,并且D::f的返回类型中的类类型具有与B::f的返回类型中的类类型相同的cv限定,或者小于B::f的返回类型中的类类型

协方差仅允许用于指针、左值/右值引用。我猜您不想通过引用或指针返回枚举

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


将返回类型更改为int everywhere?这不是很好,因为其他功能保留和使用enum很重要。这样做的一个小缺点是没有意义,不过:-enum只是定义整型常量的一种方式,类型名称没有任何意义。将返回类型更改为int不会以任何方式影响程序。将返回类型更改为int everywhere?这不是很好,因为其他功能保留和使用枚举很重要。这一点的一个小缺点是没有意义,不过:-枚举只是定义
e整数常量,类型名称没有任何意义。将返回类型更改为int不会影响程序的任何方式。- 1更改虚拟函数的返回类型是不允许的,并且没有意义是不正确的C++支持协变的原始指针和引用函数结果。虽然这可能不是提问者想要的。好吧,我取消否决票。但请注意,修订中的逻辑实际上并不起作用。事实现在已经确定,推理无效的旧C++03枚举隐式转换为int,就像派生指针隐式转换为基类指针一样。指针/引用协方差的点是,您可以调用希望获得BaseData类型指针的基方法,并允许派生类进一步指定返回的对象实际上是从BaseData继承的DerivedData类型。这对枚举没有意义,因为它们不支持继承。对。但我觉得你认为这与我写的东西有关。-不改变。- 1改变虚拟函数的返回类型是不允许的,并且没有意义是不正确的C++支持协变原始指针和引用函数结果。我刚刚意识到,并且已经修复了,虽然它可能不是askk正在寻找的。好,我正在删除下注。但请注意,修订中的逻辑实际上并不起作用。事实现在已经确定,推理无效的旧C++03枚举隐式转换为int,就像派生指针隐式转换为基类指针一样。指针/引用协方差的点是,您可以调用希望获得BaseData类型指针的基方法,并允许派生类进一步指定返回的对象实际上是从BaseData继承的DerivedData类型。这对枚举没有意义,因为它们不支持继承。对。但我觉得你认为这与我写的东西有关。不是。这个解决方案会生成另一个编译错误重载函数,只是返回类型不同而已…@Yakov:请修复您的错误。很抱歉,没有你的代码,我看不出你的代码到底出了什么问题。但是我可以猜到,您无意中给了这两个函数相同的名称?也许您可以添加一个显式int-enum-base。此解决方案生成另一个编译错误重载函数,但返回类型不同…@Yakov:请修复您的错误。很抱歉,没有你的代码,我看不出你的代码到底出了什么问题。然而,我可以猜测,您无意中给了这两个函数相同的名称?也许您可以添加一个显式int-enum基。