【发布时间】:2021-11-07 08:15:05
【问题描述】:
对于这个问题的答案,我从高处和低处寻找 - 在这个论坛和一般互联网上。虽然我找到了讨论类似主题的帖子,但我现在需要做出一些设计选择,并且想知道我是否以正确的方式进行,如下所示:
在 C++ 中,我创建了 3 种数据结构:链表、二叉树和网格。我希望能够在这些数据结构中存储不同的类 - 一个可能是用于操作字符串、另一个数字等的类。现在,分配给节点的每个类都能够执行和处理比较操作标准的不等式运算符。
我认为 C++ 继承会为这个问题提供完美的解决方案 - 它允许基本“数据类”(抽象类)和所有其他数据类(例如 JString)从它继承。所以数据类会有以下不等式方法:
virtual bool isGreaterThan(const dataStructure & otherData) const = 0;
然后,JString 将从 dataStructure 继承,并且希望重写此方法,因为 isGreaterThan 显然会根据类具有不同的含义。但是,我需要的是:
virtual bool isGreaterThan(const JString & otherData) const;
我知道这不会起作用,因为参数是不同的数据类型,而 C++ 需要它来覆盖虚拟方法。我能看到的唯一解决方案是在JString 中做这样的事情:
virtual bool isGreaterThan(const dataStructure & otherData);
{
this->isGreaterThanJString(dynamic_cast<const JString&>(theSourceData));
};
virtual bool isGreaterThanJString(const JString & otherData) const;
换句话说,重写方法只是调用等效的JString,将otherData 向下转换为JString 对象,因为这将始终为真,如果不是,它无论如何都应该失败。
我的问题是:这似乎是一个可以接受的策略,还是我缺少 C++ 的一些能力。我也使用过模板,但我试图避免这种情况,因为我发现调试变得非常困难。另一种选择是尝试可以接受任何数据类型的void*,但这也会带来问题,并将负担转移到代码上,从而导致更长的类。
【问题讨论】:
-
模板、运算符重载、lambdas,也许还有
std::list应该让您顺利上路。 -
模板是我去这里的方式。老实说,我不知道为什么这会使调试变得更加复杂。编写模板类可能会有点麻烦,因为您缺少通常由 IDE 完成的自动完成功能和错误检查,但这些问题可以通过编写类来解决,但您只提到调试是一个问题。
-
你陷入了过度使用类继承的陷阱,就像“我有一把锤子,所以我需要敲的一切都必须是钉子”。公共类继承对于表示类之间的“是一种”关系是有意义的 - 而不是继承所有派生类必须专门化并且需要知道这些操作如何在所有其他派生类中完成的操作。您的情况是一些(基本上不相关的)类支持一些类似的(通用)操作。在 C++ 中,模板、函数重载和其他机制将是比类继承更可行的方法。
-
感谢您对此的反馈 - 我同意模板似乎是合适的解决方案,我可能会回到那个问题。至于彼得的帖子,这就是我对自己的疑惑。我想这就像创建一类“生物”,包括地球上所有具有不同特征和特征的数百万物种——在编程世界中,“生物”类将大得惊人。
标签: c++ generics inheritance virtual downcast