虚函数返回类型

Virtual function return type

本文关键字:返回类型 函数      更新时间:2023-10-16

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

在每个派生类中,我定义了一个enum,并尝试覆盖GetData函数return(派生类特定的enum)值;

例如:

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

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

在你的特殊情况下,你的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.

这是文章的链接

只有在用指向派生类的指针/引用替换指向基类的指针/引用时才允许更改虚函数的返回类型,因为一个可以安全地转换为另一个。虽然enum类型和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(); }
};

根据c++ 11 ISO 10.3/7:

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

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

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

—两个指针或引用具有相同的cv-限定符,并且D::f返回类型中的类类型与B::f返回类型中的类类型具有相同或更少的cv-限定符。

协方差只允许用于指针、左值/右值引用。我猜您不希望通过引用或指针返回enum。

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

现场演示

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};
    }
};