我有一个D类,它扩展了B,扩展了A.我现在想要添加一个C类,它具有与B完全相同的接口,但提供了不同的实现。所以我将其设计如下:
这不是我想要的,因为我只需要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的接口。
答案 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
B
或C
。
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 B
或new C
。
D析构函数将调用delete A
,现在您必须决定复制和分配。
我的建议不是使用A *,而是std::unique_ptr
(将使拥有的对象在D-s之间移动)或std::shared_ptr
。
如果您需要每个D都有自己的A,那么让A拥有clone
方法(在B和C中重写,分别返回new B
和new C
)并在D的复制文件中调用它并指定操作符。
答案 3 :(得分:-1)
似乎D
根本不需要继承A
(或B
或C
)。相反,它只需要在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