引用变量
1、首先我们从void creatBtree_Qian(Node<T> *&p,T t);
这个递归创建二叉树的函数说起
- 必须使用指针引用变量
- 因为指针为初始的时候,结点中我设置的左右指向指针为NULL,递归调用到
creatBtree_Qian(p->left,t);
这样的函数时候,p->left为NULL如果不用引用,只是使用指针作为参数,那么传递的只是NULL这个值给了p,p是新创建的一个指针变量,然后接下来p指向结点,结点存入值后进入下一个调用,函数体结束的时候这个p就会丢失,使用引用之后,相当于真的把这个指向指针传递了过去,之后将这个指针指向新结点,是可以被“记住”的
- 因为指针为初始的时候,结点中我设置的左右指向指针为NULL,递归调用到
2、其次对引用变量不为空的“纠正”理解
- 引用变量不能是空不是引用变量不能为NULL
当在主函数调用void creatBtree_Qian()
这个函数的时候,我发现,将获得头结点的函数当作参数会编译报错。 即test.creatBtree_Qian(test.getRoot(),-1)
不可编译。
各种测试后首先个人认为原因是因为test.getRoot()函数,在当时是的把root=NULL,只是把这个NULL的值传了回去。相当于Node<int> *&t2=NULL
这个是不可以的。
而先把返回值NULL存入一个相应指针变量,在将这个指针变量赋给引用指针变量是可以的
即:
1 | Node<int> *t=test.getRoot(); |
这样是可以的。
所以:
1 | Node<int> *t=test.getRoot(); |
这样就正确了。
所以引用变量非空不是不能为NULL,而是不能没有任何实际地址能够赋给他
但是将构造函数改变之后,明明返回值不是NULL了却依旧报错,-个人猜测是因为return机制下返回值被保存在寄存器中等待变量来访问获取结构,所以普通指针能够访问保存,而引用变量直接获取地址,相当于起个别名罢了,但是寄存器中的数据无法提供给引用变量地址故报错。当然待求证,毕竟只是初学者
2019.12.15:猜想错误,详见下文
3、但是问题又来了
这样root不能够直接作为根创建树,毕竟这样t只是接受了test.getRoot()返回的值而已,之后的一系列操作也都是基于t上创建二叉树,传递不到root。
所以我们干脆这样:
main函数中直接随便创建一个结点指针,传入创建函数中,最后创建完毕将这个指针赋给root:
于是我们在创建函数中添加一句:root=p
1 | template <class T> |
虽然每个创建函数结束都会调用一次root=p,但是根据递归函数的特点,在这个函数中,当跳出最后一次函数体的时候,root的值一定是会被根节点赋予,而不是分支结点
最后总结一下一个个人猜测的结论:任何函数的返回值都不能直接赋给一个引用变量
2019.12.15补充:关于树的封装,见:二叉排序树的实现和应用,同时猜测结论正确!下面是原因
引用不能绑定到临时对象!可以简单理解它相当于一个右值(例如a=2的2,他是不能被引用的)。
而解决问题,再根据二叉排序树的实现和应用中返回引用的理解,这里我们把getRoot()返回类型设为引用即可将test.creatBtree_Qian(test.getRoot(),-1)
的编译正确
最基础的,但是正确的理解:左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式).其他深入理解,见下文推荐阅读:
具体了解左值右值: