C ++继承:在运行时确定继承的方法

时间:2013-01-24 07:11:37

标签: c++ multiple-inheritance extend

我有一个D类,它扩展了B,扩展了A.我现在想要添加一个C类,它具有与B完全相同的接口,但提供了不同的实现。所以我将其设计如下: diamond

这不是我想要的,因为我只需要D的实例来扩展B或C而不是两者,但是,这仅在运行时确定。上面设计的问题当然是如果我在D中调用一个在B和C中实现的方法,它的含糊不清。

所以我想要的是在运行时创建一个B或C的实例,然后将其转换为D.每次D的实例调用一个继承的方法时,它应该使用它的一个原始对象。 / p>

我是否需要在每个方法调用周围使用typeid和if / else,或者是否有更优雅的方法来执行此操作?

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();

然后将D的实例传递给另一个用D做东西的类(E),因此,我无法修改D的接口。

4 个答案:

答案 0 :(得分:2)

我认为你的继承方式是错误的,你所做的是定义你想要调用类D的所有方法,因为类A中的虚方法,类B和C都有自己的实现那些方法。

然后使用A *类型的数据结构,用指向B和C类型对象的指针填充它,然后调用需要在包含类型A *的指针的数据结构中的所有对象上调用的方法然后,vtable机制将确保使用B类或C类的实现,具体取决于实际对象的类型。

请参阅What is the difference between a concrete class and an abstract class?

答案 1 :(得分:1)

听起来你只是想要

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;

除非D实际上有自己的行为?然后你可以查看decorator pattern,并使D成为B或C实例的装饰器。

修改:您的D课程根本不需要继承任何A BC

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

将上述示例中的A *a替换为D d

答案 2 :(得分:0)

C ++是一种静态类型的语言。无论你在类型声明中做什么都在编译时详细阐述,因此D的继承图在运行时无法定义。

你可能需要的是将A作为B和C的具体多态性基础(包含所有相关方法虚拟,包括析构函数)(具体实现)和D“所有者A “,通过包含A * thet,将根据输入在D版本中分配给new Bnew C

D析构函数将调用delete A,现在您必须决定复制和分配。

我的建议不是使用A *,而是std::unique_ptr(将使拥有的对象在D-s之间移动)或std::shared_ptr

如果您需要每个D都有自己的A,那么让A拥有clone方法(在B和C中重写,分别返回new Bnew C)并在D的复制文件中调用它并指定操作符。

答案 3 :(得分:-1)

似乎D根本不需要继承A(或BC)。相反,它只需要在B的实例或C的实例中调用函数。

你可以这样实现:

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();
        }
};

可以像这样使用:

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