关于c++模板二段名字查找(two phase name lookup)的思考

目录

1. 问题提出

2. 代码实现 

3. 导致的原因

4. 解决方法

 5. 参考链接


1. 问题提出

今天在写二叉搜索树的模板类的时候选择继承了二叉树的模板类,但在二叉搜索树的方法内部直接调用二叉树的成员变量m_root(根节点)和m_size(记录存储的元素个数)时,系统报错,查询了相关资料发现是因为c++标准中,模板类采取的是二段名字查找方法,先上代码

 

2. 代码实现 

#ifndef BINARYTREE_H
#define BINARYTREE_H
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;

//节点类
template<typename E>
class Node{
    public:
        E m_element;
        
        //左子节点
        Node<E>*m_left;

        //右子节点
        Node<E>*m_right;

        //父节点
        Node<E>*m_parent;

        Node(E element,Node<E>*parent){
            m_element=element;
            m_parent=parent;
            m_left=0;
            m_right=0;
        }

        //判断节点是否为叶子节点
        bool isLeaf(){
            return (m_left==NULL)&&(m_right==NULL);
        }

        bool hasTwoChildren(){
            return (m_left!=NULL)&&(m_right!=NULL);
        }
};

template<typename T>
class BinaryTree{
    private:
        //前序遍历
        void preorderTraversal(Node<T>*node){
            if(node==NULL)  return;
            cout<<node->m_element<<" ";
            preorderTraversal(node->m_left);
            preorderTraversal(node->m_right);
        }

        //中序遍历
        void inorderTraversal(Node<T>*node){
            if(node==NULL)  return;
            inorderTraversal(node->m_left);
            cout<<node->m_element<<" ";
            inorderTraversal(node->m_right);
        }

        //后序遍历
        void postorderTraversal(Node<T>*node){
            if(node==NULL)  return;
            postorderTraversal(node->m_left);
            postorderTraversal(node->m_right);
            cout<<node->m_element<<" ";
        }

        //递归实现获得二叉树的高度
        int height1(Node<T>*node){
            if(node==NULL)  return 0;
            return max(height1(node->m_left),height1(node->m_right))+1;
        }

        //迭代实现获得二叉树的高度
        int height2(Node<T>*node){
            if(node==NULL)  return 0;

            int height=0;

            //存储每一层的元素数量
            int levelSize=1;

            queue<Node<T>*>q;
            q.push(node);

            while(!q.empty()){
                Node<T>*temp=q.front();
                q.pop();
                levelSize--;
                if(temp->m_left!=NULL){
                    q.push(temp->m_left);
                }
                if(temp->m_right!=NULL){
                    q.push(temp->m_right);
                }

                if(levelSize==0){
                    height++;
                    levelSize=q.size();
                }
            }

            return height;
        }

        //递归翻转二叉树
        void invert1(Node<T>*node){
            if(node==NULL)  return;

            Node<T>*temp=node->m_right;
            node->m_right=node->m_left;
            node->m_left=temp;

            invert(node->m_left);
            invert(node->m_right);
        }

        //迭代翻转二叉树
        void invert2(Node<T>*node){
            if(node==NULL)  return;
            queue<Node<T>*>q;
            q.push(node);
            while(!q.empty()){
                Node<T>*temp=q.front();
                q.pop();

                Node<T>*tmp=temp->m_left;
                temp->m_left=temp->m_right;
                temp->m_right=tmp;

                if(temp->m_left!=NULL){
                    q.push(temp->m_left);
                }
                if(temp->m_right!=NULL){
                    q.push(temp->m_right);
                }
            }
        }

    protected:
        int m_size;

        //根节点
        Node<T>*m_root;

        //前驱结点,中序遍历中前一个节点
        Node<T>*predesessor(Node<T>*node){
            if(node==NULL)  return NULL;

            //有左子树
            if(node->m_left!=NULL){
                Node<T>*p=node->m_left;

                while(p->m_right!=NULL){
                    p=p->m_right;
                }
                return p;
            }

            //无左子树
            if(node->m_left==NULL){
                while((node->m_parent!=NULL)&&(node==node->m_parent->m_left)){
                    node=node->m_parent;
                }

                //parent为空,或者node为父节点的右子节点
                return node->m_parent;
            }
        }

        //后继节点
        Node<T>*successor(Node<T>*node){
            if(node==NULL)  return NULL;

            //有右子树
            if(node->m_right!=NULL){
                Node<T>*s=node->m_right;

                while(s->m_left!=NULL){
                    s=s->m_left;
                }
                return s;
            }

            //无右子树
            if(node->m_right==NULL){
                while((node->m_parent!=NULL)&&(node==node->m_parent->m_right)){
                    node=node->m_parent;
                }
            }
            //parent为空,或者node为父节点的左子节点
            return node->m_parent;
        }

        //用于获得节点
        Node<T>*node(T element){
            Node<T>*curr=m_root;
            while(curr!=NULL){
                int cmp=compare(element,curr->m_element);
                if(cmp==0)  return curr;

                if(cmp>0){
                    curr=curr->m_right;
                }

                if(cmp<0){
                    curr=curr->m_left;
                }
            }
            return NULL;
        }

        //返回值等于0代表e1==e2,返回值大于0代表e1大于e2,返回值小于0,e1小于e2
        int compare(T&e1,T&e2){
            if(e1>e2)   return 1;
            if(e1<e2)   return -1;
            else    return 0;
        }

    public:
        BinaryTree(){
            m_size=0;
            m_root=0;
        }

        int size(){return m_size;}

        bool empty(){return m_size==0;}

        void clear(){
            queue<Node<T>*>q;
            q.push(m_root);
            while(!q.empty()){
                Node<T>*temp=q.front();
                q.pop();
                if(temp->m_left!=NULL){
                    q.push(temp->m_left);
                }
                if(temp->m_right!=NULL){
                    q.push(temp->m_right);
                }
                delete temp;
            }
            m_size=0;
        }

        //前序遍历接口
        void preorderTraversal(){
            preorderTraversal(m_root);
        }

        //中序遍历接口
        void inorderTraversal(){
            inorderTraversal(m_root);
        }

        //后序遍历接口
        void postorderTraversal(){
            postorderTraversal(m_root);
        }

        //层序遍历
        void levelorderTraversal(){
            if(m_root==NULL)  return;
            queue<Node<T>*>q;
            q.push(m_root);
            while(!q.empty()){
                Node<T>*temp=q.front();
                q.pop();
                cout<<temp->m_element<<" ";
                if(temp->m_left!=NULL){
                    q.push(temp->m_left);
                }
                if(temp->m_right!=NULL){
                    q.push(temp->m_right);
                }
            }
        }

        //判断是否为完全二叉树
        bool isComplete(){
            if(m_root==NULL)    return false;

            queue<Node<T>*>q;
            q.push(m_root);

            bool leaf=false;

            while(!q.empty()){
                Node<T>*temp=q.front();
                q.pop();
                
                if(leaf&&(!temp->isLeaf())){
                    return false;
                }

                if(temp->hasTwoChildren()){
                    q.push(temp->m_left);
                    q.push(temp->m_right);
                }else if((temp->m_left==NULL)&&(temp->m_right!=NULL)){

                    return false;
                }else{
                    //左不为空,右为空或者左右都为空
                    //从下一个节点开始,全是叶子节点
                    leaf=true;
                }
            }
            return true;
        }

        //高度接口
        int height(){
            return height2(m_root);
        }

        //翻转二叉树接口
        void invert(Node<T>*node){
            invert2(node);
        }
};

#endif

这是BinarySearchTree.h文件(已修改过)

#ifndef BINARYSEARCHTREE_H
#define BINARYSEARCHTREE_H
#include"..\05-BinaryTree\BinaryTree.h"

template<typename T>
class BinarySearchTree:public BinaryTree<T>{
    private:
        //删除curr节点
        void remove(Node<T>*curr){
            if(curr==NULL)  return;

            //度为2
            if(curr->hasTwoChildren()){
                //找到后继节点
                Node<T>*s=this->successor(curr);

                //覆盖
                curr->m_element=s->m_element;
                
                curr=s;
                
            }

            //删除curr,curr必然是度为1或是0
            Node<T>*replacement=0;
            if(curr->m_left!=NULL){
                replacement=curr->m_left;
            }else{
                replacement=curr->m_right;
            }

            //curr是度为1的节点
            if(replacement!=NULL){
                replacement->m_parent=curr->m_parent;

                //curr为度为1的节点,并且是根节点
                if(curr->m_parent==NULL){
                    this->m_root=replacement;
                    delete curr;
                }
                if(curr==curr->m_parent->m_left){
                    curr->m_parent->m_left=replacement;
                    delete curr;
                }else if(curr==curr->m_parent->m_right){
                    curr->m_parent->m_right=replacement;
                }

            }else{
                //curr为叶子节点
                //是根节点
                if(curr->m_parent==NULL){
                    delete this->m_root;
                    this->m_root=0;
                }else{
                    //curr是叶子节点,但不是根节点
                    Node<T>*parent=curr->m_parent;

                    if(curr==parent->m_left){
                        delete curr;
                        parent->m_left=NULL;
                    }else{
                        delete curr;
                        parent->m_right=NULL;
                    }
                }
            }
            this->m_size--;
        }

    public:
        BinarySearchTree(){
            this->m_size=0;
            this->m_root=0;
        }

        void add(T element){
            //是添加的第一个节点
            if(this->m_root==NULL){
                this->m_root=new Node<T>(element,NULL);
                this->m_size++;
                return;
            }

            //添加的不是第一个节点
            Node<T>*node=this->m_root;

            //存父节点
            Node<T>*parent=this->m_root;

            int cmp=0;
            while(node!=NULL){
                cmp=this->compare(element,node->m_element);
                parent=node;

                if(cmp>0){
                    node=node->m_right;
                }else if(cmp<0){
                    node=node->m_left;
                }else{
                    //覆盖
                    //自定义对象
                    node->m_element=element;
                }
            }
            
            Node<T>*newNode=new Node<T>(element,parent);
            if(cmp>0){
                parent->m_right=newNode;
            }else{
                parent->m_left=newNode;
            }

            this->m_size++;
        }

        //删除element的节点
        void remove(T element){
            remove(this->node(element));
        }
};

#endif

3. 导致的原因

原先在binarySearchTree.h文件中,我并没有加入this指针,vscode报错提示为m_size,m_root,node都未声明(not declared)。查阅了相关资料之后发现,c++标准中,对于模板类中名字查找,分为两个阶段进行:

        1. 第一阶段是模板定义阶段。系统只检查语法的正确性,并且只处理独立(non-dependent)(指该变量不依赖传进来的参数模板)的变量。因为BinaryTree依赖于BinarySearchTree的参数列表T来实现,所以BinaryTree是非独立的,于是编译器认为BinaryTree<T>不存在,但仍合法,所以认为BinaryTree<T>的所有函数和变量都为非成员属性。这也是not decalred的原因

        2.第二阶段是模板实例化阶段。系统会处理非独立的变量。

4. 解决方法

添加了this指针之后,编译器对m_size, m_root和node函数的查找会推迟到第二阶段,因为相当于告诉编译器,这就是成员函数或者属性。在子类找不到便会去父类中查找

 5. 参考链接

1. Two phase name lookup for C++ templates-Why?

https://stackoverflow.com/questions/12561544/two-phase-name-lookup-for-c-templates-why

2. c++模板&二段式名字查找

https://blog.csdn.net/imjtrszy/article/details/71893704

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值