简体   繁体   English

我可以限制多态性的行为吗?

[英]can i restrict behaviour of polymorphism?

So i'm trying to implement a binary search tree and avl tree.所以我正在尝试实现二叉搜索树和avl树。 Each of these classes using different but similar types of nodes.这些类中的每一个都使用不同但相似类型的节点。 The classes for nodes look like this:节点的类如下所示:

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() {}
};

This mostly works.这主要是有效的。 Any node can have connexions with any other node , and any avl_node with any other avl_node .任何node都可以与任何其他node建立联系,任何avl_node可以与任何其他avl_node建立联系。 The issue that I think of is that a node could technically have a parent or children avl_node because of polymorphism, and I wouldn't want that to happen.我想到的问题是,由于多态性,一个node在技术上可能有一个父节点或子节点avl_node ,我不希望这种情况发生。 Although I can avoid that by being careful, i wouldn't want it to be possible at all.虽然我可以通过小心来避免这种情况,但我根本不希望它成为可能。 Is there a way?有办法吗?
ps I want to keep the classes related ps我想保持类相关

If it's enough, you could explicitly delete the version of constructor that would take an avl_node*如果足够,您可以显式删除将采用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() {}
};

Of course, this solution is not foolproof.当然,这种解决方案并非万无一失。 If you brought an avl_node hidden behind a node pointer, the compiler wouldn't be able to tell (and since polymorphism is mainly dynamic, you would only be protected in this specific case where you attempt to assign the pointer directly)如果您将avl_node隐藏在node指针后面,编译器将无法判断(并且由于多态性主要是动态的,因此您只会在尝试直接分配指针的特定情况下受到保护)

This would compile.这将编译。

avl_node myavl;
node n(0, static_cast<node*>(&myavl));

You could try dynamic-casting in the node constructor to tell if it's an avl_node being passed (your nodes would need a vtable for that), but that would make it impossible to call the constructor like that from the avl_node constructor.您可以尝试在node构造函数中进行动态转换,以判断它是否是传递的avl_node (您的节点需要一个 vtable),但这将使得无法像从avl_node构造函数那样调用构造函数。

Another option would be making a separate constructor intended specifically for the subclass另一种选择是制作一个专门用于子类的单独构造函数

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() {}
};

You can get rid of polymorphism and avoid code duplication by using a class template for the base, and members that depend on the template argument.您可以通过使用 class 模板作为基类和依赖于模板参数的成员来摆脱多态性避免代码重复。

Example:例子:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM