I have a number of types that all relate to each other in terms of them being ‘derived’ from one another. I’d need a way to do is
relationships, which made me initially think of classes, but I realized that other than the is
relationships, there would be no reason to use classes as each ‘type’ of data function the exact same way. I’d also thought of enums, but since there is no way to extend or inherit from enums it was a poor choice.
For context (this being my specific example):
I have a number of different kinds of resources that all are ‘types’ so that they can be used in conjunction with an int to denote how much of that resource is available. I have several different kinds of these resources, such as foods, metals, building materials etc. Within the food category would be something like wheat or corn; under metals would be copper, iron, gold etc. Since all of these are still just ‘resources’ and have no actual functionality other than typing, it seems pointless to use classes and OO inheritance.
How would I implement this kind of data type without resorting to using classes?
4
If there are no functions to inherit, composition of structs may be more favorable than class inheritance. The concept of “composition over inheritance” may apply here, see:
Wikipedia
Popular SO Answer to this issue
Although the above examples use classes, an alternative implementation could use structs:
Composition with C structs
1
What you described is very much possible without checking is
relationships.
An object oriented design should rely on interfaces, not implementations. That means, code like this:
if (o is Derived1)
{
do_something_with_derived1(o);
}
else if (o is Derived2)
{
do_something_with_derived2(o);
}
Should be turned into
o.do_something_virtual(context);
Essentially, you move the responsibility of “doing something” from the caller to the callee. The caller only triggers this action. The callee knows its own type and can act accordingly. If there is any context on the calling site that you would use in the operation, you pass that as a parameter.
The key here is the virtual method, which allows for a dynamic dispatch. This removes the strong dependency to each implementation and “type checking” boilerplate on the calling site. The calling site can even call future implementations.
Another possible approach is a data driven design. Entity Component systems are a flexible solution that can be used to avoid complicated class hierarchies when each base class would only add a little bit of functionality (in your example: the kind and amount of resource).
5