0

I have a class D that extends B which extends A. I now want to add a class C that has exactly the same interface as B but provides a different implementation. So I design it as the following: diamond

This is not exactly what I want, as I only need an instance of D to either extend B or C and not both, however, this is only determined at runtime. The problem with the design above is of course that if I call a method in D which is implemented both in B and C, its ambiguous.

So what I would like to have is to create an instance of either B or C at runtime and then cast it into D. Every time an instance of D calls an inherited method it should use the one of its original object.

Do I need to fiddle with typeid and if/else around each method call or is there a more elegant way to do this?

class A{ 
virtual f1();
virtual f2();
}

class B : public virtual A{
f1();
f2();
f3();
}

class C : public virtual A{
f1();
f2();
f3();
}

class D : public B, public C{
f4(){f1(); f3)};
}

...
D* d = new D();
E* e = new E(d);
e->d->f1();
e->d->f4();

Instances of D are then passed to another class (E) which does stuff with D and therefore, I cannot modify the interface of D.

Community
  • 1
  • 1
hlitz
  • 635
  • 6
  • 24
  • This is a very strange request and difficult to assess in such abstract terms. You might get better answers if you state the problem more concretely. – Marcelo Cantos Jan 24 '13 at 07:14
  • 1
    Does D have any behavior of its own? – Karthik T Jan 24 '13 at 07:17
  • if u need instance of D to either extend B or C and not both, try you design 2 class, D1 and D2 where D1 extend B and D2 extend C – someone_ smiley Jan 24 '13 at 07:38
  • @someone_smiley Yes I though about that but I need to pass D to another class, which I cannot modify and which expects D and neither D1 or D2 – hlitz Jan 24 '13 at 07:46
  • 1
    What is the actual definition of the methods of E that you pass an instance of D to? – wich Jan 24 '13 at 07:59

4 Answers4

2

I think you're having inheritance the wrong way around, what you do is define all the methods that you want to call on what you call class D as virtual methods in class A, class B and C both have their own implementation of those methods.

Then you use a data structure of type A*, fill that with pointers to objects of type B and C and you call the methods that you need to call on all the objects in the data structure that contains pointers of type A*, the vtable mechanism will then make sure that the implementation of class B or C is used depending on what the actual object's type is.

See What is the difference between a concrete class and an abstract class?

Community
  • 1
  • 1
wich
  • 16,709
  • 6
  • 47
  • 72
1

It sounds like you just want

class A{
    virtual void DoMagic() = 0;

};  
class B{
    virtual void DoMagic(){};

};  
class D{
    virtual void DoMagic(){};

};

...
bool INeedB = true;//or false
A* a;
if(INeedB){
    a= new B();
}else{
    a = new C();
}
a->DoMagic(); // will call the appropriate method based on the value of INeedB;

Unless D actually has behavior of its own? Then you can look at decorator pattern, and make D the decorator of an instance of B or C.

Edit: Your D class doesnt need to inherit any of A B or C at all.

class D{
    D(A* aObj):a(aObj){}
    void f3(){ a->f1();a->f2();}
    A *a;
};

Replace A *a in above example with D d

Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • B, C, D all extend the behavior of their parents. – hlitz Jan 24 '13 at 07:41
  • 1
    @hlitz you still need to explain better, but from your sample code, it isnt necessary for D to extend A at all.. – Karthik T Jan 24 '13 at 07:48
  • @hlitz This is a crude version of the decorator pattern, If your D actually does need to inherit, I suggest you take a good look at the Decorator Pattern, sounds like what you need – Karthik T Jan 24 '13 at 07:54
  • Yes I do need D to extend B and C. Note that f1, f2 in B,C are not virtual also. A is purely virtual (an interface definition), so I don't _need_ to extend it but its good design practice, and it wouldn't solve my problem anyway. I'll have a look at the decorator pattern. – hlitz Jan 24 '13 at 17:10
0

C++ is a statically-typed language. Whatever you do with type declaration is elaborated at compile time, hence the inheritance graph of D cannot be defied at runtime.

What you probably need is to have A as a polymorphic base (with all relevant method virtual, included the destructor) for both B and C (concrete implementation of that), and D an "owner of an A", by containing an A* thet will be assigned at D construction to a new B or new C depending on input.

D destructor will call delete A, and now you have to decide about copy and assignment.

My suggestion is not to use an A*, but a std::unique_ptr (will make the owned object movable between D-s) or std::shared_ptr.

In case you need each D to have its own A, then let A to have a clone method (overridden in B and C, to return a new B and new C respectively) and call it in D's copy ctor and assign operator.

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63
-1

It seems like D doesn't need to inherit from A (or B or C) at all. Instead it just needs to call function in either an instance of B or an instance of C.

You can implement it something like this:

class A
{
public:
    virtual void f1();
    virtual void f2();
};

class B : public A;
class C : public A;

class D
{
   A* b_or_c;

public:
    D(A* a_pointer)
        : b_or_c(a_pointer)
        {}

    void f3()
        {
            b_or_c->f1();
            b_or_c->f2();
        }
};

Can be used like this:

B b;  // An instance of B
C c;  // An instance of C

D d1(&b);
D d2(&c);

d1.f3();  // Will cause `f1` and `f2` in the object `b` to be called
d2.f3();  // Will cause `f1` and `f2` in the object `c` to be called
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621