C++ 继承和虚函数,其中基本参数需要用派生参数替换
C++ Inheritance & Virtual Functions Where Base Parameters require Replacement with Derived Ones
我在这个论坛和一般互联网上寻找过这个问题的答案。虽然我找到了讨论类似主题的帖子,但我现在需要做出一些设计选择,并且想知道我是否以正确的方式进行设计,如下所示:
我在 C++ 中创建了 3 种数据结构:链表、二叉树和网格。我希望能够在这些数据结构中存储不同的 classes - 一个可能是 class 来操作字符串,另一个是数字等。现在,这些 classes 中的每一个,分配到节点,能够执行和处理标准不等运算符的比较操作。
我认为 C++ 继承会为这个问题提供完美的解决方案——它会允许基础“数据 class”(抽象 class)和所有其他数据 classes,例如 JString
,从它继承。因此数据 class 将具有以下不等式方法:
virtual bool isGreaterThan(const dataStructure & otherData) const = 0;
然后,JString
将从 dataStructure
继承,并且希望覆盖此方法,因为 isGreaterThan
显然会根据 class 具有不同的含义.然而,我需要的是:
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*
,但这也会带来问题,并将负担转移到代码上,导致更长的 classes.
LSP 意味着对基 class 的引用的操作必须有效并且具有与基和派生 class 实例上的操作相同的语义,当这些操作是引用多态时。
您的示例未通过此测试。基础 isGreaterThan 声称适用于所有数据结构,但它没有。
我会在您的容器中制作 dataStructure 参数类型模板。那么你就知道存储数据的具体类型了。
查看 std list 以了解链表模板的外观。
我现在将介绍在上述建议不正确的 0.1% 情况下您可以执行的复杂的附加步骤。
如果这导致问题,因为模板膨胀,您可以创建一个多态容器来强制存储数据的类型,或者使用薄模板包装器或运行时测试。存储后,您将盲目地转换为已知的存储类型,并存储如何 copy/compare/etc 在 C 或 C++ 样式的多态方法中表示类型。
这是一个关于这种方法的 8 岁有趣的谈话:https://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil
我在这个论坛和一般互联网上寻找过这个问题的答案。虽然我找到了讨论类似主题的帖子,但我现在需要做出一些设计选择,并且想知道我是否以正确的方式进行设计,如下所示:
我在 C++ 中创建了 3 种数据结构:链表、二叉树和网格。我希望能够在这些数据结构中存储不同的 classes - 一个可能是 class 来操作字符串,另一个是数字等。现在,这些 classes 中的每一个,分配到节点,能够执行和处理标准不等运算符的比较操作。
我认为 C++ 继承会为这个问题提供完美的解决方案——它会允许基础“数据 class”(抽象 class)和所有其他数据 classes,例如 JString
,从它继承。因此数据 class 将具有以下不等式方法:
virtual bool isGreaterThan(const dataStructure & otherData) const = 0;
然后,JString
将从 dataStructure
继承,并且希望覆盖此方法,因为 isGreaterThan
显然会根据 class 具有不同的含义.然而,我需要的是:
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*
,但这也会带来问题,并将负担转移到代码上,导致更长的 classes.
LSP 意味着对基 class 的引用的操作必须有效并且具有与基和派生 class 实例上的操作相同的语义,当这些操作是引用多态时。
您的示例未通过此测试。基础 isGreaterThan 声称适用于所有数据结构,但它没有。
我会在您的容器中制作 dataStructure 参数类型模板。那么你就知道存储数据的具体类型了。
查看 std list 以了解链表模板的外观。
我现在将介绍在上述建议不正确的 0.1% 情况下您可以执行的复杂的附加步骤。
如果这导致问题,因为模板膨胀,您可以创建一个多态容器来强制存储数据的类型,或者使用薄模板包装器或运行时测试。存储后,您将盲目地转换为已知的存储类型,并存储如何 copy/compare/etc 在 C 或 C++ 样式的多态方法中表示类型。
这是一个关于这种方法的 8 岁有趣的谈话:https://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil