views:

282

answers:

8

I am using a base class and there are 5 child classes currently for it. Some of the functions are similar for 3 of the children but not all of them. I cannot introduce a new level of hierarchy as some methods are repeated in child 1,2,3 and some in 2,3,4.

How best can I avoid overriding the methods in all 3 children and repeating the code.

+1  A: 

Create a mix-in class and have the children with the method in common inherit from it also. For example:

class Base {
  public:
    virtual commonFunction() { /* default implementation */ };
}; 

class Mixin {
  public:
     virtual notSoCommonFunction() { /* default implementation */ };
};

class D1 : public Base {
  public:
     virtual commonFunction() { /* override implementation */ };
};

class D2 : public Base, public Mixin {
  public:
     virtual commonFunction() { /* override implementation */ };
     virtual notSoCommonFunction() { /* override implementation */ };
};

class D3 : public Base, public Mixin {
  public:
     virtual commonFunction() { /* override implementation */ };
     virtual notSoCommonFunction() { /* override implementation */ };
};

So all classes D1, D2, D3 implement (and optionally override) commonFunction, but only D2 and D3 implement (and optionally override notSoCommonFunction).

Tyler McHenry
A: 

You could add a new intermediate class with protected methods for the different implementations of each function. Then in the child classes override the methods from the original base class and call the appropriate protected methods from this new intermediate class.

class Base {
    public void foo() { /* ... */ }
    public void bar() { /* ... */ }
}

class Middle extends Base {
    protected void foo1() { /* ... */ }
    protected void foo2() { /* ... */ }
    protected void bar1() { /* ... */ }
    protected void bar2() { /* ... */ }
}

class Child1 extends Middle {
    // Use default foo()
    public void bar() { bar1(); }
}

class Child2 extends Middle {
    public void foo() { foo1(); }
    public void bar() { bar2(); }
}

class Child3 extends Middle {
    public void foo() { foo2(); }
    // Use default bar()
}
John Kugelman
+3  A: 

When you don't want to use multiple inheritance, you could also use composition.

Put the common code into one special class and add instances of the class to those subclasses which need the code. You then could either navigate to the functionality or wrap the call into access methods (inline).

Juergen
This is probably the better overall strategy. In general, creating complex inheritance hierarchies primarily for the purpose of centralizing functionality (rather than creating meaningful type relationships) leads to code that becomes unmanageable and error-prone.
Tyler McHenry
+1  A: 

Or you could explore Strategy pattern. Sometimes, HAS-A relation is better choice than IS-A. Of course, I don't know if your problem allows introduction of the pattern

Damir Zekić
A: 

Most of the answers above talk of using a new class, but the method I am using calls many other methods of the class and also uses some of the class instance variables. If I use a mixin or compose a new class, I wont be able to implement the method.

Arvind
Edit your question instead of posting this as an answer.
Johannes Schaub - litb
I would assume, that in this case there is some "base"-functionality that all this classes have in common. Either this base functionality belongs to the existing base class or it would be worthwhile to refactor it out into a new hierarchy level between the actual base class and the subclasses. But of course it really depends on your actual class structure and can be a difficult design decission. We can only give some hints as long the actual situation is that abstract. Composition could work -- but also could not. Also it could be possible to use a composition class that uses the containing.
Juergen
Also, you need to stick to a single login; the question was opened by user ID 126271 while this answer was posted by user ID 126282. See http://stackoverflow.com/questions/53598/how-can-one-link-merge-combine-associate-two-stack-overflow-accounts-users-anon for instructions on how to re-merge user IDs.
ephemient
A: 

If you need access to the other members of the class, you could use templated mixins that static_cast the this pointer to the appropriate type:

template<class T>
class M1Mixin {
public:
   int m1() {
     return static_cast<T*>(this)->some_value;
   }
};


class Base {
public:
  int some_value;
  ...
};

class A : public Base, M1Mixin<A> {
  ...
};

It's not pretty, but it works.

sth
A: 

The code review can wait before you get the satisfactory answer for this, right? Cool. :-)

A: 

Another solution that might work is the following:

Suppose that the base class is called MyBaseClass, the child classes are ChildClass1 through ChildClass5, and the function that you want to duplicate looks like this:

public int foo(Object args)
{...}

Now what you can do is create a separate class (call it "HelperFunctions" or some such) with a static method:

public static int fooHelper(BaseClass theClass, Object args)
{insert duplicated code here}

and then have the foo functions in the classes you want call that helper function.

This has a few advantages:

  1. You're not creating new objects or changing the type hierarchy. Since the helper function is static you can call it without needing any new objects.
  2. You can still call methods of the class, because you are passing in the object of type BaseClass, so you can call methods on it just like you would from within the class.

Most of the answers above talk of using a new class, but the method I am using calls many other methods of the class and also uses some of the class instance variables. If I use a mixin or compose a new class, I wont be able to implement the method.

I'm not sure I understand what the problem is. At least in my solution, you're passing in the object, so you can call whatever methods and access instance variables on the object you want. Is the problem that the instance variables or methods you want to access are private so you can't access them outside the class? In that case you can easily solve it by declaring the helper function to be a friend function (just google "c++ friend function" for tutorials on how to use them)

Alex319