Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly express two derived class functions with the same implementation in C++?

Currently, I'm in a situation where I have some base class and many subclasses. The subclasses must override several virtual methods, however, sometimes the implementation for a virtual method in one subclass is exactly identical to another subclass. Should I just copy and paste the implementation code into the other subclass or is there a way to express an implementation for both subclasses at once?

The code below demonstrates my problem.

class A
{
    virtual void foo1() = 0;
    virtual void foo2() = 0;
};

class B : public A
{
    void foo1();
    void foo2();
};

class C : public A
{
    void foo1();
    void foo2();
};

class D : public A
{
    void foo1();
    void foo2();
};

void B::foo1()
{
     // Same implementation of foo1 as C
}

void C::foo1()
{
     // Same implementation of foo1 as B
}

void D::foo1()
{
     // Different implementation of foo1
}

void B::foo2()
{
     // Different implementation of foo2
}

void C::foo2()
{
     // Different implementation of foo2
}

void D::foo2()
{
     // Different implementation of foo2
}

Can I somehow combine implementation for B and C?

Note: I explicitly wrote out foo2, because otherwise subclass B and C would be identical in every way.

I'm wondering about the case when there are many (much larger than this toy example) subclasses and also they are inheriting many virtual functions with some virtual functions having the same implementation. In other words, a situation where creating a subclass every time a function coincidentally has the same implementation would clutter the whole inheritance structure.

like image 868
MathGeek Avatar asked Jun 07 '19 20:06

MathGeek


2 Answers

Add an intermediate proxy class:

class BC : public A {
    void foo1();
};

class B : public BC {
    void foo2();
};

class C : public BC {
    void foo2();
};

As @Fureeish mentioned - don't repeat yourself.

What to do, if amount of classes / functions is massive:

Do the same. In the worst case, you'll end with (roughly) the same amount of code, with more classes, but fewer functions. Even then this is a net win, because you've removed a lot of code redundancy, and while inheritance structure is worse, the code quality is much better. In practice, such dense "collision matrix" suggests something is wrong with the classes themselves. Maybe those intermediate classes you up end creating should be written in the first place? In all cases, reducing code redundancy is a big win.

like image 79
Radosław Cybulski Avatar answered Nov 15 '22 22:11

Radosław Cybulski


I see two options:

  • Move the common code to some interface (possibly private) and simply call that interface inside your two functions.

  • Provide a default implementation and simply don't override it, i.e. instead of making foo1 pure virtual, just implement the default behaviour there.

Obviously it is possible that there is no default way of doing what foo1 should do. Then I suggest sticking with the first option.

like image 24
Fureeish Avatar answered Nov 15 '22 23:11

Fureeish