Reputation: 2172
I had a class A
, which used some enums something like this:
enum DataType
{
First,
Second,
Third
}
And consecutively they had some values assigned to them which was used in code.
Now, I have to write another class B
which is very similar to class A
, for which I'm planning to make a class Parent
and derive both class A
and class B
from it. But, I want to reuse the enum DataType
in both classes.
The problem being, that these enum
values should be different for both class A
and class B
.
For class A
enum DataType
{
First = 1,
Second = 2 ...
}
For class B
enum DataType
{
First = 18,
Second = 19 ...
}
One naive approach that comes to mind is define a virtual function in both classes, having a switch case
, so instead of using the enum, I'll have to call the virtual function and use what it returns.
But, is there a better way to do it? By using some inheritance property, which I'm not aware of?
Upvotes: 1
Views: 1600
Reputation: 41800
I'd simply send the type of the derived class to the parent class function:
// 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;
}
}
};
Then in your derived classes:
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);
}
};
This pattern avoid templating the whole base class, and you can still use virtual polymorphism. You only templatize the parts that needs the enum in a protected section.
Upvotes: 1
Reputation: 238421
A simple solution is to define a enum DataType
in each of the members. This introduces no runtime or storage overhead. But in this case the behaviour is static; The user has access to the enum only based on the static type. If the enum values obey a similar pattern to that in your example, you may be able to generate the enum, or even the entire class with a template.
A dynamic approach is what you suggested: Use a virtual function. That has a bit of overhead, but provides runtime polymorphism. In this case, the user can access the enum specific to the dynamic type without knowing what that type is.
These two approaches can even be combined so that you have both.
Upvotes: 2
Reputation: 136485
One way:
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.
}
Upvotes: 1
Reputation: 377
Your DataTypes for A and B are distinct types, so the Parent class has to be a template:
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;
}
Note that I used enum class instead of (old-style) enum to prevent running into ambiguity of the enum values.
Upvotes: 1