使用合理的引用参数实现接口的自说明
在指针和引用的小文中,主要讨论了引用和指针语法层面上的区别。本文将侧重如何更加合理地利用语言对引用所作限制。
在C++中,指针是最灵活的,也是最危险的。在编程当中,我们可以使用const对指针做限制。下面对const指针做点介绍。
const Type * var; //var指针变量指向一个const Type的对象,因为对象做了const限制,故该指针只能调用Type类中,带const限制的接口。最佳情况下,该指针不会改变Type对象的内部状态。
const Type * const var; //var指针变量指向一个const Type的对象,同上,最佳情况下,该指针不会改变Type对象的内部状态。 另外指针的类型为const指针,也就是该指针变量并不能重新赋值(同引用)。
那么现在有个问题:调用Type的析构函数算不算改变Type对象的状态?
个人理解,析构一个对象肯定是改变该对象的状态。那么如果说const限制意味着不能改变对象状态,那么编译器理应对delete 指向const Type的对象操作报错。不过编译器并没有这么做。为什么?假设编译器限制析构const Type的对象,由于析构函数本身的特殊性,这将导致所有的const Type对象都无法析构。这是极其不合理。
因此,不管指针做什么样的限制,都无法限制调用者直接delete 指针所指向的对象。
那么如果使用const引用能否限制用户的不合理行为吗?这是可以的。
引用本身仅仅是变量的别名,并不控制对象的生存期。对于非const的引用,使用者可以方便地改变引用对象的状态;如果想让用户无法改变引用对象的状态,只要加上const限制即可。
区别了const引用和非const引用之后,很容易想到,将传入参数声明为const引用,将传出的参数声明为非const引用。另外,程序中还经常使用函数返回值来传递对象的内部变量。同样的道理,我们也可以通过将返回值限制为const引用来限制使用者不小心改变对象的内部状态。对于const的返回值,如果使用者需要改变对象状态,那么可以通过拷贝构造函数来初始化一个新对象。也就是说,const返回值可以强制用户使用新的对象拷贝,从而避免易错的对象clone.
当然,如果使用引用来传递参数,为了易用性,应该编写拷贝构造函数和重载赋值运算符。