我正在尝试构建一个类,使其子类具有C ++ 11 enum class
属性,并具有关联的setter / getter:
class Base {
public:
enum class MyEnum {
A,
B
} my_enum;
Base() : my_enum(MyEnum::A) {}
MyEnum get() { return my_enum; }
void set(const MyEnum &ME) { my_enum = ME; }
};
class Derived : public Base {
public:
Derived(): Base() {
my_enum = MyEnum::B;
}
};
int main(int argc, char *argv[])
{
Derived Deriv;
// No problems!
Deriv.get() == Derived::MyEnum::B;
return 0;
}
到目前为止,真好!
但是,我希望派生类能够重新定义MyEnum
枚举类,而不必一直重新实现setter / getter /属性:
// Base as before
class Derived : public Base {
public:
enum class MyEnum {
C,
D
}; // intention: to override Base's "my_enum" attribute
Derived(): Base() {
my_enum = MyEnum::C;
// ERROR: cannot convert 'Derived::MyEnum' to 'Base::MyEnum'
}
};
int main(int argc, char *argv[])
{
Derived Deriv;
// ERROR: no match for 'operator==' for types 'Base::MyEnum' and 'Derived::MyEnum'
Deriv.get() == Derived::MyEnum::C;
return 0;
}
我明白问题是什么;我只是在寻找能够在这种情况下重用代码的最简洁方法。
最好只通过继承(或者更确切地说,Derived()类只能通过从Base()派生的行为来使用该功能)。
有什么建议吗?
答案 0 :(得分:1)
编译器是正确的:尽管枚举Base::MyEnum
和Derived::MyEnum
是在通过继承连接的类中定义的,但枚举本身并不被认为是相关的。它们碰巧具有相同的非限定名称,这对编译器没有任何意义:就编译器而言,两个枚举类型是无关的。
如果你考虑枚举在引擎盖下实现的方式,这是有道理的:尽管强类型,枚举仍然是小的整数常量。由于两者不相关,Base::MyEnum::A
与Derived::MyEnum::C
具有相同的值,并且在运行时没有任何东西可以让您区分这两个值。
除了将所有枚举值转储到基类的enum
(这会将机会扩展到您自己的库之外)之外,您几乎无法做到:C++ enumerations do not support inheritance,并且通常不是很灵活。
答案 1 :(得分:1)
这是一个坏主意,不会起作用。
Base::get()
返回MyEnum {A, B}
,那么每个派生类必须有get()
,并返回MyEnum {A, B}
。这就是继承的全部内容(而不是代码重用,或者不仅仅是代码重用)。您可以通过将类变为模板而不是依赖继承来实现代码重用。
答案 2 :(得分:1)
你可以使Base
成为一个模板,由枚举类型参数化,并使用traits类提供一个“默认”枚举类型,可以通过派生类型进行专门化。
template<typename T>
struct MyEnumTraits
{
enum class type {
A,
B
};
static const type default_value = type::A;
};
template<typename T = void>
class Base {
public:
typedef typename MyEnumTraits<T>::type MyEnum;
MyEnum my_enum;
Base() : my_enum(MyEnumTraits<T>::default_value) {}
MyEnum get() { return my_enum; }
void set(const MyEnum &ME) { my_enum = ME; }
};
class Derived;
template<>
struct MyEnumTraits<Derived>
{
enum class type {
C,
D
};
static const type default_value = type::C;
};
class Derived : public Base<Derived> {
// ...
但是现在不同的派生类型会有不同的基类,这可能不是你想要的。您可以通过保留非模板Base
并将getter和setter移动到从Base
派生的中间类模板来解决这个问题,然后派生类型从中派生出来。
class Base { ... };
template<typename T = void> class GetterSetterImpl : public Base { ... };
class Derived : public GetterSetterImpl<Derived> { ... };