I am facing an OOP problem in GUI design, but let me illustrate it with animals example. Lets have following setup:
It is only natural for animal has-a Teeth, but now I need something like interface for has-a relationship. For example, if I have a vector of animals, how can I make every Bite() if they can?
std::vector<Animal *> animals;
animals.push_back(new dog());
animals.push_back(new fly());
animals.push_back(new cat());
void Unleash_the_hounds(std::vector<Animal *> animals)
{
//bite if you can!
}
I came up with several solutions but none seems to be perfectly fitting:
1.) every class with Teeth also implements interface IBiting. This solution, however, introduces a lot of code duplication, I would need to "implement" Bite() in every class:
class Cat : public Animal, public IBiting {
Teeth teeth;
public:
virtual void Bite() { teeth.Bite(); }
}
2.) Give every animal Teeth, but only allow some to use them. Note: syntax can be wrong - it is only illustration
class Animal{
static cosnt bool canBite = false;
Teeth teeth;
public:
void Bite() { this->canBite ? teeth.Bite() : return; }
}
class Cat {
static cosnt bool canBite = true;
}
3.) More inheritance - create class BitingAnimal and derive it. Well, this could work, but what if I needed derive (non)flying animals, some of them have teeth.
class Animal{}
class BitingAnimal : public Animal {
Teeth teeth;
}
and use as BitingAnimal.teeth.Bite()
4.) multiple inheritance. This often is discouraged, and impossible in most languages, plus it is not logical for Cat to be Teeth.
class Cat : public Animal, public Teeth {
}
5.) Enum of classes that can bite - weird only by sound of it.
Or am I only over-complicating it and missed something important?
An alternative that you didn't mention is to just provide an abstraction for the teeth, but implement the biting in the base class. This reduces the duplication because the derived classes only need to specify how to access the teeth instead of how to bite. By returning a pointer to the teeth, we can allow a null pointer to indicate that the animal has no teeth. Here is an example:
#include <vector>
struct Teeth {
void bite() { }
};
struct Animal {
virtual Teeth *teethPtr() = 0;
void biteIfYouCan() { if (teethPtr()) teethPtr()->bite(); }
};
struct Dog : Animal {
Teeth teeth;
Teeth *teethPtr() override { return &teeth; }
};
struct Fish : Animal {
Teeth *teethPtr() override { return nullptr; }
};
int main()
{
Dog dog;
Fish fish;
std::vector<Animal *> animals {&dog,&fish};
for (auto animal_ptr : animals) {
animal_ptr->biteIfYouCan();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With