I'm using multiple inheritance in C++ and extending base methods by calling their base explicitly. Assume the following hierarchy:
Creature / \ Swimmer Flier \ / Duck
Which corresponds to
class Creature { public: virtual void print() { std::cout << "I'm a creature" << std::endl; } }; class Swimmer : public virtual Creature { public: void print() { Creature::print(); std::cout << "I can swim" << std::endl; } }; class Flier : public virtual Creature { public: void print() { Creature::print(); std::cout << "I can fly" << std::endl; } }; class Duck : public Flier, public Swimmer { public: void print() { Flier::print(); Swimmer::print(); std::cout << "I'm a duck" << std::endl; } };
Now this presents a problem - calling the duck's print
method calls its respective base methods, all of which in turn call the Creature::print()
method, so it ends up being called twice-
I'm a creature I can fly I'm a creature I can swim I'm a duck
I would like to find a way to make sure the base method is called only once. Something similar to the way virtual inheritance works (calling the base constructor on the first call, then only assigning a pointer to it on successive calls from other derived classes).
Is there some built-in way to do this or do we need to resort to implementing one ourselves?
If so, how would you approach this?
The question isn't specific to printing. I wondered if there's a mechanism for extending base methods and functionality while keeping the call order and avoiding the diamond problem.
I understand now that the most prominent solution would be to add helper methods, but I just wondered if there's a "cleaner" way.
The solution to the diamond problem is to use the virtual keyword. We make the two parent classes (who inherit from the same grandparent class) into virtual classes in order to avoid two copies of the grandparent class in the child class.
The diamond problem The diamond problem occurs when two superclasses of a class have a common base class. For example, in the following diagram, the TA class gets two copies of all attributes of Person class, this causes ambiguities. For example, consider the following program.
Explanation: The diamond problem arises when multiple inheritance is used. This problem arises because the same name member functions get derived into a single class. Which in turn creates ambiguity in calling those methods.
Virtual inheritance solves the classic “Diamond Problem”. It ensures that the child class gets only a single instance of the common base class. In other words, the Snake class will have only one instance of the LivingThing class. The Animal and Reptile classes share this instance.
Most likely this is a XY problem. But ... just don't call it twice.
#include <iostream> class Creature { public: virtual void identify() { std::cout << "I'm a creature" << std::endl; } }; class Swimmer : public virtual Creature { public: virtual void identify() override { Creature::identify(); tell_ability(); std::cout << "I'm a swimmer\n"; } virtual void tell_ability() { std::cout << "I can swim\n"; } }; class Flier : public virtual Creature { public: virtual void identify() override { Creature::identify(); tell_ability(); std::cout << "I'm a flier\n"; } virtual void tell_ability() { std::cout << "I can fly\n"; } }; class Duck : public Flier, public Swimmer { public: virtual void tell_ability() override { Flier::tell_ability(); Swimmer::tell_ability(); } virtual void identify() override { Creature::identify(); tell_ability(); std::cout << "I'm a duck\n"; } }; int main() { Creature c; c.identify(); std::cout << "------------------\n"; Swimmer s; s.identify(); std::cout << "------------------\n"; Flier f; f.identify(); std::cout << "------------------\n"; Duck d; d.identify(); std::cout << "------------------\n"; }
I'm a creature ------------------ I'm a creature I can swim I'm a swimmer ------------------ I'm a creature I can fly I'm a flier ------------------ I'm a creature I can fly I can swim I'm a duck ------------------
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