我可以限制多态性的行为吗?
Posted
技术标签:
【中文标题】我可以限制多态性的行为吗?【英文标题】:can i restrict behaviour of polymorphism? 【发布时间】:2021-08-01 12:47:27 【问题描述】:所以我正在尝试实现二叉搜索树和 avl 树。这些类中的每一个都使用不同但相似类型的节点。节点的类如下所示:
class node
protected:
int key;
node* parent, * left, * right;
public:
node(int key, node* parent = nullptr) :key(key), parent(parent), left(nullptr), right(nullptr)
~node()
;
class avl_node : public node
private:
int height;
public:
avl_node(int key, int height, avl_node* parent = nullptr) :node(key, parent), height(height)
~avl_node()
;
这主要是有效的。任何node
可以与任何其他node
建立联系,任何avl_node
可以与任何其他avl_node
建立联系。我想到的问题是,由于多态性,node
在技术上可能有一个或多个父级或子级avl_node
,我不希望这种情况发生。虽然我可以通过小心来避免这种情况,但我根本不希望它成为可能。有没有办法?p.s.我想保持类相关
【问题讨论】:
如果你不想要多态,那为什么还要使用子类呢?您能否详细说明您的代码有什么问题?你想达到什么目标? 如果你想要容器的类型安全实现,你应该研究模板,而不是多态——这正是它们被发明的原因。否则,您将与该语言的核心功能作斗争。 你不能既保持类的相关性又避免多态性。为什么要让它们保持关联? @molbdnilo 避免重复代码 @stack_overflow_nickname 你不需要相关的类。 【参考方案1】:如果足够,您可以显式删除将采用 avl_node*
的构造函数版本
class node
protected:
int key;
node* parent, * left, * right;
public:
node(int key, node* parent = nullptr) :key(key), parent(parent), left(nullptr), right(nullptr)
node(int, avl_node*) = delete;
~node()
;
当然,这个解决方案并非万无一失。如果您将 avl_node
隐藏在 node
指针后面,编译器将无法分辨(并且由于多态性主要是动态的,因此只有在尝试直接分配指针的特定情况下才会受到保护)
这会编译。
avl_node myavl;
node n(0, static_cast<node*>(&myavl));
您可以尝试在 node
构造函数中进行动态转换,以判断它是否是正在传递的 avl_node
(您的节点需要一个 vtable),但这将使得无法从avl_node
构造函数。
另一种选择是为子类创建一个单独的构造函数
class node
protected:
int key;
node* parent, * left, * right;
node(int key, avl_node* parent) : key(key), parent(parent), left(nullptr), right(nullptr)
public:
node(int key, node* parent = nullptr) :key(key), parent(parent), left(nullptr), right(nullptr) /* do something to not allow avl_node* to be passed */
~node()
;
【讨论】:
我这里有个问题。由于avl_node
是从node
派生的,因此在'node' 类内部,甚至没有定义avl_node
。我尝试包含您建议的以下行node(int, avl_node*) = delete;
,但出现此错误:syntax error: identifier 'avl_node'
只需向前声明您需要的内容(或 node(int, class avl_node*)
与 class
关键字已经算作声明)【参考方案2】:
您可以摆脱多态性并使用类模板作为基类模板和依赖于模板参数的成员。
例子:
template<typename T>
class node
protected:
int key;
node* parent, * left, * right; // Note: these are actually 'node<T>'.
public:
node(int key, node* parent = nullptr)
: key(key), parent(parent), left(nullptr), right(nullptr)
void set_parent(node* p) parent = p;
;
class avl_node : public node<avl_node>
private:
int height;
public:
avl_node(int key, int height, avl_node* parent = nullptr)
: node(key, parent), height(height)
;
class silly_node : public node<silly_node>
public:
silly_node() : node(0)
;
int main()
// Fine
avl_node an(0, 1);
// Fine
avl_node bn(0, 1, &an);
// Also fine
bn.set_parent(&an);
// Fine
silly_node sn;
// Compilation error
avl_node cn(0, 1, &sn);
// Also compilation error
bn.set_parent(&sn);
【讨论】:
为什么node
实际上是node<T>
?这是如何运作的?另外,我不清楚如何创建node
类的实例。
在模板内部,模板名称本身是指当前的实例化。而你不能创建 node
实例是重点; node
实例化不相关,但从基本模板的实例化继承代码。
所以我的想法是在我的binary_search_tree
类中使用silly_node
并在我的avl_tree
类中使用avl_node
?
silly_node
只是说明编译错误的示例。顾名思义,它很愚蠢,不应该用于任何事情。这个想法是为每种类型的树创建一个实例化 - 例如class binary_search_node : public node<binary_search_node> ...
。
我在这里又遇到了一个问题。所以我创建了一个binary_search_tree
类,它有一个成员root
,它的类型是node*
。在我尝试做root=root->left
的方法中,但我收到以下错误:t_node<node>*
类型的值不能分配给node*
类型的实体。附: t_node
是模板类,node
是从它派生的类以上是关于我可以限制多态性的行为吗?的主要内容,如果未能解决你的问题,请参考以下文章