我听说dynamic_cast
&的选项rtti(但成本很高)或虚拟功能,但我不确定哪个是最好的!
假设我有以下示例
我有一个包含2个子类Human
和Man
的父类Woman
。
Human
ofc提供了一些标准方法。
但是,我们可以说Woman
与Man
有不同的方法。
为什么我需要知道对象的实例?
让我们说我的功能只允许人类作为参数。
所以参数可以是男人或女人。
但是对于进一步的操作,我需要知道Human对象实际上是Man
还是Woman
,然后将其转换为其中一个。
我认为在这种情况下使用虚函数不是一个好主意,因为子类有不同的方法数量?!
答案 0 :(得分:2)
你是对的 - 如果你发现自己需要施法或rtti,这是一个好兆头,也许你需要重新考虑你的设计。
但是“继承”的整个想法是你可以用专门的方法和数据来定义一个“人”类,这些方法和数据只与“男性”有关,一个不同的类“女人”有她自己的专业数据和方法......和这些类的父类“人”是他们共有的方法。
此外,点击通常应该使用“人”类(通常不应该关心实例恰好是“男人”还是“女人”。客户应该知道 little 关于类实例的可能性 - 足以完成它的工作;不再需要。
最后,如果“男人”和“女人”做同样的操作,但需要不同 ......这就是虚拟方法的用武之地。
这些链接可能有所帮助:
答案 1 :(得分:1)
你这样做:
switch (human->gender) {
case GenderMan:
doTheManlyThing((Man*)human);
break;
case GenderWoman:
doTheWomanlyThing((Woman*)human);
break;
default:
abort("Unknown gender, stop the world");
}
故意使用符合C语言的语法。如果你要像往常一样回去做什么,为什么不去寻找完整的蒙太奇呢?
如果您使用typeid(*human)
代替整数类型指示符,或者if (dynamic_cast<whatewer*>) ...
就像今天的孩子一样,那么概念上也是如此,只是稍微(或很多)慢。
替代方案当然是
human->doTheHumanThing(); // a call to a virtual function
// possibly with an empty body
// in case one of the genders
// "has more actions" than the other(s)
但真正的程序员不使用虚函数。他们打开了类型ID,他们喜欢它。
另一种选择是访客模式,它又是一堆虚拟功能,只能水平放置而不是垂直放置,可以这么说。我不希望这个答案成为访客的第11521273条描述,所以我只会推荐你the universal font of wisdom。
答案 2 :(得分:0)
如果您发现自己因分析而陷入瘫痪,请记住过早优化的规则(即不要这样做)。继续吧。您可以在以后的路上选择其他路径(只是不要等待太久)。 :)
在每篇文章中,我都读到了dynamic_cast带来的成本。我没有 测试了它 -
这种担心有一个简单的解决方案,它是编程的基本技能:自己测试。
关于您对RTTI / dynamic_cast性能表现的担忧(在评论中):同时应用过早优化的规则。除非您发现问题,否则虚拟函数调用相对较快,您不应该关心。除非您有性能问题的证据,否则实际上是否存在性能问题? Bjarne Stroustrup在他的一本C ++书中提到了人们对虚拟调度性能的怀疑。如今,测试显示50,000,000个虚拟调度调用只需不到一秒钟。在我的分析中,虚拟呼叫的性能几乎与非虚拟呼叫相同。开销是统计噪音(除了最罕见的情况之外)。
利用当今的处理器和缓存架构,结合智能C ++编译器,我们应该不再担心虚拟调度或RTTI的开销。在我的PC上,我可以使用dynamic_cast&lt;&gt;来测试50,000,000个对象的向量。在一秒钟内,包括if语句和每个分支路径的另一条指令。
// populate vector
std::vector<A*> avec;
for (int i = 0; i < 50000000; i++) {
if (i % 2)
avec.push_back(new A());
else
avec.push_back(new B());
}
clock_t begin = clock();
int j = 0;
for (int i = 0; i < 50000000; i++) {
if (dynamic_cast<B*>(avec[i])) {
j += 1;
}
else
j -= 1;
}
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
cout << "dynamic_cast: " << elapsed_secs << std::endl;
cout << "j=" << j << std::endl;
PS:如果您尝试使用此代码,我建议使用较小的矢量并重复多次重复。我实际上编译并运行为x64项目,但关键是不要分配一个5000万项目向量,重点是显示跨越一堆随机对象指针的虚拟调度。对于32位,它可能会产生内存不足错误。
如果C ++虚拟调度对于您的目的而言太慢,那么您可能不太关心优雅的面向对象设计,而是更多关于调整每个最后一个周期。在这种情况下,删除虚函数,广泛使用内联函数,或者使用非面向对象的C语言或汇编语言编写。
答案 3 :(得分:0)
我实际上找到了另一种解决方案。 我正在使用的框架实际上为此提供了解决方案。 如果(对象 - &GT;的getclass() - &GT; IsChildOf(APlayerCharacter :: StaticClass()))
这实际上对我很有帮助!