c++ - C++ 多态继承问题的优雅解决方案
问题描述
想象一下我们正在使用的库有两个类 Dog 和 Bowl
class Bowl;
class Dog
{
Bowl* m_bowl;
};
class Bowl
{
Dog* m_owner;
};
Dog 拥有一个指向其关联的 Bowl 对象的指针。Bowl 还拥有一个指向其关联 Dog 对象的指针。一切都很好。我现在派生了一个新的类 FancyDog,它扩展了 Dog 的功能
class FancyDog : public Dog
{
// Do the fancy dog stuff
};
一切都很好,至少在 FancyDog 需要用一个新的闪亮的豪华碗替换她无聊的、旧的普通碗之前。
class FancyBowl : public Bowl
{
// Extra functions only relevant for FancyBowls
};
FancyDog 应该如何与其新的 FancyBowl 交互?我只能想到两个选项,这两个选项都“不错”,但都没有感到非常满意
除了她通过 Dog 继承的 Bowl 指针对象外,FancyDog 还拥有一个 FancyBowl 指针。从技术上讲,它们可能属于不同的类,但从概念上讲,FancyDog 现在拥有两个指向同一个对象的不同指针,这让我感觉不像是一个优雅的编码器。如果我们是迂腐的,我们也在浪费记忆,在大多数情况下,这无疑是微不足道的。
每次需要访问派生接口时,FancyDog 动态将其 Bowl 指针转换为 FancyBowl 指针。如果我们只需要这样做一两次,也许性能影响并不大,但同样不会让我感到温暖和模糊。
这只是一个经典的性能内存权衡还是有更优雅的解决方案?
PS 请注意,如果我们尝试让 FancyBowl 跟踪 Dog,我们将遇到同样的问题。
解决方案
这是 Dog/Bowl 作者设计不佳的问题。考虑以下改进:
class Bowl;
class Dog
{
virtual Bowl* getBowl() = 0;
};
class Bowl
{
Dog* m_owner;
};
现在 FancyDog 的实现可以持有一个 FancyBowl 并返回一个指向它的指针,这没问题。
本质上,这个问题是一个方差——因为 Dog 类保留分配给m_bowl
指针的权利,所以你永远不能保证它总是指向 FancyBowl,因为 Dog 可能会重新分配它。在第一种情况下,您保证 FancyDog 总是有一个 FancyBowl,但是您失去了 Dog 和 FancyDog 看到同一个碗的保证。在第二种情况下,您不知道碗将是 FancyBowl,但您知道您至少总是使用同一个碗。
如果 Dog 类声明了一个更小的接口,它只需要该类实际需要的内容(即您有一个 Bowl 可供它读取),那么问题就消失了。如果您不喜欢简单的运行时多态 getter,则上述还有更复杂的静态变体。
推荐阅读
- python - Python 探查器时间不会累加
- c# - ASP.NET Core .NET 6 预览版 7 Windows 服务
- c - C中的while循环重新打印以前的语句
- c++ - (C++) 读取矩阵文件的最快方式(任意大小)
- intersystems-iris - $Increment 和 $Sequence 函数有什么区别?
- parquet - 如何追加到镶木地板文件以及它如何影响分区?
- android - 滚动屏幕直到列表到达顶部
- docker - docker compose v3 的部署资源的行为限制了“cpus”参数设置(是绝对数量还是可用核心的百分比)
- javascript - 多个车把文件未读取 css 文件
- python - 在给定唯一列值的情况下,熊猫数据框如何删除以小于数字的行长为条件的行?