Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove code duplication for virtual class members in C++ inheritance

I have got myself into a strange issue now. Ill write a really simplified version of the same.

class Base
{
public:
  virtual int func1()=0;
  virtual int func2()=0;
protected:
  int n;
};

class der1: public Base
{
  // implements the virtual functions of the base and uses the protected data 
  // members of the base.
};

class der2: public Base
{
  // implements the virtual functions of the base and uses the protected data 
  // members of the base.
}

Now the problem.... both der1 and der2 implements the virtual functions of base pretty much the same way. But some other classes (der3, der4) has their own implementations. But still need to inherit from base. How do i refactor the code to remove the code duplication in an oop manner?

like image 536
lifeOfPi Avatar asked Oct 21 '18 09:10

lifeOfPi


2 Answers

Here's one solution using an intermediate layer of another abstract base class:

class Base12 : public Base {
protected: 
    int commonFuncStuffA() {
       // Commonly used stuff 
    }

    int commonFuncStuffB() {
    }
};

class der1: public Base12
{
public:
    virtual int func1() {
        n = commonFuncStuffA();
    }
    virtual int func2() {
        n = somethingElse;
    }
};

class der2: public Base12
{
public:
    virtual int func1() {
        n = commonFuncStuffA();
    }
    virtual int func2() {
        n = commonFuncStuffB();
    }
};

What I'd do for real production code design looks a bit different though.

  1. Declare an interface for the pure virtual functions

    struct IMyInterface {
        virtual int func1() = 0;
        virtual int func2() = 0;
        virtual ~IMyInterface {}
    };
    
  2. Provide a abstract base class with the commonly used data members and functions

    class BaseImpl : public IMyInterface {
    protected: 
        int n;
        int commonFuncStuffA() {
            // Commonly used stuff 
        }
    
        int commonFuncStuffB() {
            // Commonly used stuff 
        }
    };
    
  3. Provide implementations of the interface in the finally derived classes

    class der1: public BaseImpl {
    public:
        virtual int func1() {
            n = commonFuncStuffA();
        }
        virtual int func2() {
            n = somethingElse;
        }
    };
    
    
    class der2: public BaseImpl {
    public:
        virtual int func1() {
            n = commonFuncStuffA();
        }
        virtual int func2() {
            n = commonFuncStuffB();
        }
    };
    
    class der3: public IMyInterface {
    public:
        virtual int func1() {
            // Some completely different implementation of the interface
        }
        virtual int func2() {
            // Some completely different implementation of the interface
        }
    };
    
    class der4: public IMyInterface {
    public:
        virtual int func1() {
            // Some completely different implementation of the interface
        }
        virtual int func2() {
            // Some completely different implementation of the interface
        }
    };
    
like image 195
πάντα ῥεῖ Avatar answered Sep 27 '22 22:09

πάντα ῥεῖ


Option 1

You may consider using your most common implementation in the Base class. The main feature or drawback of this method is that the base class would no longer be abstract. If this is a problem, go to option 2.

Maybe you can even cope with differences in the derived classes by using the template method pattern to extract the differences in protected virtual functions invoked by the template method.

In anyway, for derived classes that need a completely different appoach, you'd just override the the Base class' method.

class Base
{
public:
  virtual int func1();
  virtual int func2()=0;
protected:
  virtual void f1_specific_part1()=0;
  virtual void f1_specific_part2()=0; 
  int n;
};
int Base::func1() { // common skeleton of the algorithm
     ...  
     f1_specific_part1(); 
     ... 
     f1_specific_part2(); 
     ...
}     

class Der1: public Base
{ 
protected:
 void f1_specific_part1() override;  // Implements the specific variation
 virtual void f1_specific_part2() override;       
};

Option 2

You may consider to factorize the common code of the derived classes into a protected method of the Base class.

The override of the pure virtual function would then just call the base class protected common function (for der1 and der2) or just use their own implementation that is completely different (for der3 and der4).

class Base
{
public:
  virtual int func1()=0;
  virtual int func2()=0;
protected:
  int common_part1_funct1(); // implements some common parts 
  int common_part2_funct1();
  int n;
};

class Der1: public Base
{
...
  int func1() override { 
     common_part1_funct1();
     ...
     common_part2_funct1(); 
     ... 
  }
};

Option 3 ?

Important remark: My answer assumes that there are many commonalities between most of the derived classes. However if you have only a small subset of derived classes that share some commonalities, then the answer of Evg would be would be more appropriate.

like image 40
Christophe Avatar answered Sep 27 '22 22:09

Christophe