Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling identically named methods in base classes

Base class A has a subclass B, and B has a subclass C. A implements a virtual method doStuff(), B does not, and C does. From C, I want to call A's implementation of doStuff() (I do this from within C's implementation of doStuff() but that shouldn't really matter.) Should I call:

A::doStuff();

Or:

B::doStuff();

The first seems more clear because it refers to the actual implementation. On the other hand, the second might be more useful if I later decide that B needs to doStuff() differently than A. Which is more standard? Which is more dangerous?

I was a little surprised that B::doStuff() didn't trigger any warnings, but I suppose that by definition B has an implementation even if it's from the base class. Can the chain of base classes and implementations be arbitrarily long and complicated? For example, if I had A through Z, each a subclass of the previous one, could I have implementations anywhere in the chain, and does calling any class's method just go 'up the chain' until it finds an implementation?

like image 788
Luke Avatar asked Nov 05 '22 01:11

Luke


1 Answers

First, in regards to the last paragraph, yes, you're absolutely right.

Next up, for the main question:

It's a matter of logic which should be treated on a case-to-case basis. You're the only one who can decide whether you want to call the logic from B or from A, even if B::doStuff() isn't yet implemented. There's no right answer.

However, you should look into the template method pattern. My guess is that if you want C to call something from A and later you decide that you want D (sibling of C) to do the same thing, you're duplicating code. So I'd take a different approach:

class A
{
private:
   void doAStuff(); //doesn't have to be here
public:
   virtual void doStuff()
   {
      doAStuff();
   }
   void doAStuffAndStuff();
   {
      doAStuff();
      doStuff();
   }
}

class B : A
{
public:
   virtual void doStuff(); //or not
}

class C : B
{
public:
   virtual void doStuff();
}

IMO this is more intuitive. Say I have an A* a, I don't know the dynamic type of a:

  • if I want to call doStuff() with the logic in the most derived class, I call doStuff().
  • if I want to call doStuff() with the logic in the most derived class, but I also want the logic from A, I call doAStuffAndStuff().

I'm stating this approach as an alternative. I'm not saying it necessarily applies to your case, but it might.

like image 94
Luchian Grigore Avatar answered Nov 09 '22 06:11

Luchian Grigore