Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ diamond problem - How to call base method only once

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.

like image 890
O. Aroesti Avatar asked Apr 24 '19 12:04

O. Aroesti


People also ask

How do you avoid the diamond problem in multiple inheritance?

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.

What is diamond problem how can we handle this problem explain with example?

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.

Why does diamond problem arise due to multiple inheritance?

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.

What is diamond problem in multiple inheritance how it is resolved in C++?

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.


1 Answers

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"; } 

Output:

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 ------------------ 
like image 116
Swordfish Avatar answered Sep 22 '22 14:09

Swordfish