hlitz
hlitz

Reputation: 655

C++ inheritance: determine inherited methods at runtime

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.

Upvotes: 0

Views: 1462

Answers (4)

Emilio Garavaglia
Emilio Garavaglia

Reputation: 20759

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.

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409432

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

Upvotes: -1

Karthik T
Karthik T

Reputation: 31962

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

Upvotes: 1

wich
wich

Reputation: 17157

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?

Upvotes: 2

Related Questions