重写派生类中的枚举值

Overriding enum values in derived class

本文关键字:枚举 派生 重写      更新时间:2023-10-16

我有一个class A,它使用了一些枚举,如下所示:

enum DataType
{
    First,
    Second,
    Third
}

并且连续地为他们分配了一些在代码中使用的值。

现在,我必须写另一个与class A非常相似的class B,我计划为此做一个class Parent并从中得出class Aclass B。但是,我想在两个类中重用enum DataType

问题是,这些enum值对于class Aclass B都应该不同。

对于class A

enum DataType
{
    First = 1,
    Second = 2 ...
}

对于class B

enum DataType
{
    First = 18,
    Second = 19 ...
}

我想到的一种天真的方法是在两个类中定义一个虚函数,有一个switch case,所以我必须调用虚函数并使用它返回的内容,而不是使用枚举。

但是,有没有更好的方法呢?通过使用一些我不知道的继承属性?

一个简单的解决方案是在每个成员中定义一个enum DataType。这不会引入运行时或存储开销。但在这种情况下,行为是静态的;用户只能根据静态类型访问枚举。如果枚举值遵循与示例中类似的模式,则可以使用模板生成枚举甚至整个类。

您建议采用动态方法:使用虚拟函数。这会产生一些开销,但提供了运行时多态性。在这种情况下,用户可以访问特定于动态类型的枚举,而无需知道该类型是什么。

这两种方法甚至可以结合使用,以便同时拥有这两种方法。

我只是将派生类的类型发送到父类函数:

// parent not templated!
struct Parent {
    // with this pattern, stuff1 could be virtual:
    // virtual void stuff1() = 0;
protected:
    // static because we can access private
    // member through the self object
    template<typename T>
    static void stuff1_impl(T const& self) {
        auto value = /* get the switched on value */;
        switch(value) {
        case T::DataType::First:
            // things for the case1
            break;
        case T::DataType::Second:
            // things for the case1
            break;
        }
    }
};

然后在派生类中:

struct A : Parent {
    enum struct DataType {
        First = 1, Second
    };
    //               v---- if virtual, add override
    void stuff1() /* override */ {
        stuff1_impl(*this);
    }
};
struct B : Parent {
    enum struct DataType {
        First = 10, Second
    };
    //               v---- if virtual, add override
    void stuff1() /* override */ {
        stuff1_impl(*this);
    }
};

此模式避免模板化整个基类,并且您仍然可以使用虚拟多态性。您只模板化受保护部分中需要枚举的部分。

现场示例

A

和 B 的数据类型是不同的类型,因此 Parent 类必须是模板:

template<typename DataType>
class Parent
{
public:
    // example method
    virtual bool isFirst(DataType value) const
    {
        // do something with value, e. g. 
        return (value == DataType::First);
    }
};
enum class DataTypeA
{
    First = 1,
    Second = 2
};
class A : public Parent<DataTypeA>
{
};
enum class DataTypeB
{
    First = 18,
    Second = 19
};
class B : public Parent<DataTypeB>
{
};
int main()
{
    A a;
    B b;
    std::cout << "a.isFirst(DataTypeA::First): " << (a.isFirst(DataTypeA::First) ? "true" : "false") << std::endl;
    std::cout << "a.isFirst(DataTypeA::Second): " << (a.isFirst(DataTypeA::Second) ? "true" : "false") << std::endl;
    std::cout << "b.isFirst(DataTypeB::First): " << (b.isFirst(DataTypeB::First) ? "true" : "false") << std::endl;
    std::cout << "b.isFirst(DataTypeB::Second): " << (b.isFirst(DataTypeB::Second) ? "true" : "false") << std::endl;
    return 0;
}

请注意,我使用了枚举类而不是(旧式(枚举,以防止遇到枚举值的歧义。

一种方式:

template<int EnumBegin>
struct Parent {
    enum DataType {
        First = EnumBegin,
        Second, // == First + 1
        Third   // == Second + 1
    };
};
struct A : Parent<0> {};
struct B : Parent<10> {};
int main() {
    std::cout << A::Second << 'n'; // Outputs 1.
    std::cout << B::Second << 'n'; // Outputs 11.
}