由于dynamic_cast
,类是从一个父级继承并且它们的多态方法返回多态实例的设计是不好的设计?
以下是一个例子。
#include <iostream>
class Data{
public:
virtual void doSomething(){}
};
class DataB:public Data{};
class DataC:public Data{};
class ClassA{
public:
virtual Data* func() = 0;
};
class ClassB:public ClassA{
public:
DataB* func(){
return new DataB();
}
};
class ClassC:public ClassA{
public:
DataC* func(){
return new DataC();
}
};
int main(){
ClassA * obj = new ClassB();
Data * data = obj->func();
DataB* data_b = dynamic_cast<DataB*>(data);
if(data_b){
std::cout<<"This is DataB"<<std::endl;
}else{
DataC * data_c = dynamic_cast<DataC*>(data);
if(data_c){
std::cout<<"This is DataC"<<std::endl;
}
}
return 0;
}
要确定生成的实例,需要dynamic_cast
。
但是很多人说dynamic_cast
不应该是必要的。
因此,设计是否错误?
答案 0 :(得分:1)
dynamic_cast将返回NULL。此方法的问题是,如果有多个继承级别,则基类的dynamic_cast到中间子级也会返回有效指针。
设计很糟糕,因为从多态意识形态的POV来看,最好为已经在基类中声明的虚方法实现额外的功能。另一种方法是实现一些类型识别方法,由孩子覆盖,你仍然需要dynamic_cast,但只能尝试一次。
答案 1 :(得分:0)
在真/纯面向对象设计中,“按界面设计”是关键。也就是说,在不知道底层派生类的情况下应该使用Base类指针的每个地方都应该有效。
您的代码显示了众所周知的“设计模式 - 抽象工厂”,其中指出:Abstract Factory提供了一个界面,用于创建相关或依赖对象的族,而无需指定其具体类。
要确定生成的实例,需要使用dynamic_cast。
这取决于产品/系统的要求。在一段时间内生成/更改需求并且难以维护密钥“按界面设计”,因此强制使用dynamic_cast
。此外,在工作流程中,如果你真的想在派生类中使用某些东西(不是多态的)那么dynamic_cast
将是必需的,实际上并没有说'嘿!你的设计不好。'
但很多人说动态播放不应该是必要的。 同样,在启动新/新产品/系统时,设计应该是需要知道具体的对象很少或使用dynamic_cast
几乎为零。
因此,设计是否错误?
这取决于我们产品/系统的当前阶段。如果您刚刚进行产品设计,那么在使用dynamic_cast
时需要重新考虑设计。如果产品/系统过时或遗留了大量遗留代码,那么您可以使用dynamic_cast
来解决手头的问题。
答案 2 :(得分:-1)
完美设计的OOP程序不应该使用类似于黑客的强制转换。我已经更改了您的代码段,避免了动态转换。避免使用DataB *和DataC *作为抽象基类Data *可以处理它,ClassB和ClassC中的成员函数将更加同质。
#include <iostream>
class Data{
public:
virtual void doSomething(){}
};
class DataB:public Data{};
class DataC:public Data{};
class ClassA{
public:
virtual Data* func() = 0;
};
class ClassB:public ClassA{
public:
Data* func(){
return (DataB*) (new DataB());
}
};
class ClassC:public ClassA{
public:
Data* func(){
return (DataC*) (new DataC());
}
};
int main(){
ClassA * obj = new ClassB();
Data * data = obj->func();
Data* data_b = data;
if(data_b){
std::cout<<"This is DataB"<<std::endl;
}else{
Data * data_c = data;
if(data_c){
std::cout<<"This is DataC"<<std::endl;
}
}
return 0;
}