调用不在基类中的派生类函数而不进行动态强制转换,以最大程度地提高性能
Call a derived class function not in base class without dynamic casting to maximize performance
我正在C++中实施AVLTree,作为为未来项目做准备的练习。AVLTree 基本上是一个 BSTTree,但树是平衡的,即对于具有左子级 y 和右子级 z 的节点 x,x 左侧的子节点数(子级 y 和 y 的子级(与 x 右侧的子节点数相差 1 个以上。
每个节点将表示一个 int 值,并具有对父节点、可能存在的左子节点和可能存在的右子节点的引用。
class BSTNode {
protected:
int value;
BSTNode* parent;
BSTNode* left;
BSTNode* right;
...
public:
virtual void setLeftChild(BSTNode* left);
...
}
为了跟踪节点的子节点数量,我让AVLNode用两个整数扩展BSTNode,leftAffinity和rightAffinity,其中leftAffinity告诉我左侧的节点数量(与rightAffinity的右侧类似(。由于我不确保要添加的值始终是唯一的,因此在找到放置新节点的位置之前,我无法更新相关性。
class AVLNode : public BSTNode {
private:
int leftAffinity;
int rightAffinity;
...
public:
void setLeftChild(BSTNode* left) override;
...
}
一旦我成功地将节点的左子节点设置为左节点,在 AVLNode 中,我还会将当前节点的leftAffinity
更新(并递归到父节点的父节点,直到到达树的根(到left->getLeftAffinity() + left->getRightAffinity()
.
这里的问题是亲和力函数是在 AVLNode 中定义的,因此我不能在没有强制转换的情况下立即调用 left->getLeftAffinity((,因为在这里我不知道left
是 BSTNode 还是 AVLNode。我知道这个想法是让AVLNode的任何子级也只能是AVLNode,这可以通过确保任何不是AVLNode的BSTNode转换为AVLNode来强制执行。
- 我不想更改函数参数来接收 AVLNode*,因为这迫使我在 AVLNode 类中将左、右和父声明为 AVLNode*,因此我得到了重复的变量,BSTNode 类各一个,AVLNode 类各一个,即使左、右和父在 BSTNode 类中是私有的。
- 我不想使用动态强制转换,因为练习的目的是创建一个高效的树数据结构,
O(log n)
插入和获取操作的复杂性。我读过动态铸造既昂贵又应该避免,因为它通常暗示设计缺陷。
可能的方法:
- 在 BSTNode 类中创建一个"no-op"函数,该函数在 AVLNode 类中被覆盖以管理节点亲和性。这个函数不应该存在,因为它与BSTNode无关。
- 对每个添加操作进行动态强制转换,并在成功时为每个父级执行一次,直到树的根,这太昂贵了。
- 根本不为这些功能使用虚拟,这将迫使我在 AVLNode 中重载许多函数。
- 更改所有函数以接收 AVLNode* 而不是 BSTNode*,同时使用 AVLNode 中的构造函数强制将 BSTNode* 转换为 AVLNode*,但这需要动态强制转换,否则我将失去正在添加的节点的 leftAffinity 和 rightAffinity,并导致函数继承的其他问题。
对我来说,最好的选择是采用"无操作"方法,因为如果性能是关键,这种方法会起作用。
我是C++新手,所以我感谢对我所写的方法的任何想法,例如,是否有我忽略的微不足道的解决方案。在这种情况下,最好的选择是什么?
当您使用基类只是为了在不同实现之间共享代码而不是约束方法参数和返回值时,会出现这样的问题。
BSTNode
可能没有在这个角色中增加足够的价值来证明它产生的并发症是合理的,你可能应该摆脱它。
但有时这样的事情对于为难以实现的自引用类提供框架基础实现很有用。 在C++中,类型正确的方法是使用奇怪命名的奇怪重复出现的模板模式:https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
使用此模式,基类定义为将派生类作为参数的模板:
template <class NODE> class BSTNode {
int value;
NODE *left;
NODE *right;
...
}
class AvlNode : public BSTNode<AvlNode> {
...
}
现在,AvlNode
中的所有指针都具有正确的类型,并且不需要强制转换。
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 是否可以从int转换为enum类类型
- 了解 GLM- openGL 中的相机转换
- 从 16UC3 到 8UC3 的高性能 OpenCV 矩阵转换