Home > Software engineering >  How to avoid code copying in this class hierarchy?
How to avoid code copying in this class hierarchy?

Time:07-20

I have the following class hierarchy, in which the instantiation of class B has to be static in both child classes:

#include <iostream>

class A {
protected:
  virtual int get_num() const=0;
};

class B {
  int num;
public:
  int get_num() {
    return num=2;
  }
};

class D1 : public A { 
public:
  static B b;
  int get_num() const override {
    return b.get_num();
  }
};
B D1::b;

class D2 : public A {
public:
  static B b;
  int get_num() const override {
    return b.get_num();
  }
};
B D2::b;

int main() {
  D1 d1;
  std::cout << d1.get_num() << std::endl;
  D2 d2;
  std::cout << d2.get_num() << std::endl;
  return 0;
}

My problem is that the definitions of the getter functions in the children classes are CTRL C CTRL V copies of each other, which should be avoided because they do exactly the same and they might be lengthy. I am looking for a possible workaround, is there a better practice in such a case? Is this a code smell and a sign of bad design?

Edit: Classes D1 and D2 (and all their derived classes) can do different things, but the point is that the objects of the classes of each branch in the hierarchy have to work on the same instantiation of B (that's why it is declared as static). Otherwise, B could be instantiated in A. The problem is that the functions (which do the same and could be defined in A in the latter case) in the lack of instantiation of B in A, have to be defined in D1 and D2.

CodePudding user response:

If you have several classes that all have a B member and delegate some functionality to it, you should extract this bit into a common base class.

If it is not a static member you would do just this:

class Awith B : public A
{
  public: 
    int get_num() override {
     return b.get_num();
    }       
  private:
     B b;
};

Now your D1 and D2 can inherit AwithB without even knowing that B exists.

If they do need to know about B for some other reason, just change private: to protected:.

Now if the B object should be static, and each derived class should have its own separate instance, this is a bit trickier, but not by much.

template <typename Derived>
class AwithB : public A {
   ...
   static inline B b;
};

class D1 : public AwithB<D1> { ... };
class D2 : public AwithB<D2> { ... };

Here we use CRTP to inject the derived class identity to the base. Different derived classes derive from different specializations of AwithB, so each has its own static member.

  • Related