Call member function in derived class from another derived class

211 Views Asked by At

I have a program which has a base class and several derived classes which contain member functions which override the base class member functions. There is some duplication of code between the derived classes which I would like to eliminate. In particular, in one of the derived classes, one member function contains some initial processing and then the same processing as the same named member function in a different derived class.

Here is a simplified example:

#include <iostream>

class BASE 
{
public:
  virtual ~BASE() = default;
  virtual void A() { std::cout << "In BASE\n"; }
  virtual void B() { std::cout << "Shared by all instances\n"; }
  virtual void C() { std::cout << "Different in all instances\n"; }
};

class D1: BASE
{
public:
  void A() override { std::cout << "In D1\n"; }
  void C() override { std::cout << "In D1::C()\n"; }
};

class D2: BASE
{
public:
  void A() override
  {
     std::cout << "In D2\n";

     // #1
     // D1::A();        // Error cannot call D1::A() w/o object

     // #2
     // D1 *t = (D1 *) this;    // Creates recursive loop
     // t->A();                 // calling D2:A()

  }
  void C() override { std::cout << "In D2::C()\n"; }
};

int main()
{ 
  D1 d1;
  D2 d2;

  BASE *b = &d1;
  b->A();

  b = &d2;
  b->A();
}

In the example, I'd like the call to D2::A() to chain to D1::A() so I see messages from both member functions. I've tried two different ways to do this (see #1 and #2) which both get errors.

What is the correct way to do this?

1

There are 1 best solutions below

2
Wyck On

First of all, you can't do BASE *b = &d1; unless you declare class D1: public BASE. Note the use of public. Otherwise you get something like 'type cast': conversion from 'D1 *' to 'BASE *' exists, but is inaccessible. (MSVC)

Furthermore, it sounds like D2 needs to be derived from D1 so that D2::A can call D1::A in its implementation in addition to any extra functionality. This way you can "chain" as you mentioned by explicitly calling D1::A() at the end of the implementation of D2::A.

#include <iostream>

class BASE 
{
public:
  virtual ~BASE() = default;
  virtual void A() { std::cout << "In BASE\n"; }
};

class D1: public BASE
{
public:
  void A() override { std::cout << "In D1\n"; }
};

class D2: public D1
{
public:
  void A() override
  {
     std::cout << "In D2\n";

     D1::A(); // Chain to D1::A
  }
};

int main()
{ 
  D1 d1;
  D2 d2;

  BASE *b = &d1;
  b->A();

  b = &d2;
  b->A();
}

expected output:

In D1
In D2
In D1

The first "In D1" will come from calling b = &d1; b->A(); and the second and third messages "In D2, In D1" will come from calling b = &d2; b->A(); because D2::A explicitly "chains" to D1::A.