一、对于单纯的常量,用const替换#define;用内联函数替换宏函数
如果想表示一个常量,请使用const而不是#define,因为#define在预编译期被简单的替换,没有类型检查。而const变量会被编译,编译期间会进行类型检查,更加安全可靠。除了类型检查之外,由于#define只是简单的将宏名替换,所以会导致生成的目标代码更大,而const就不会
二、operator[]与const
在博客https://blog.youkuaiyun.com/Master_Cui/article/details/109532520中,operator[]的实现分成了两个版本,但是为啥const版本的operator[]需要返回const对象的引用?此外文中的operator[]实现较短,如果实现代码较多,能否用一个调用另外一个?
第一个问题:为啥const版本的operator[]需要返回const对象的引用?
如果const版本的operator[]没有返回const对象的引用,当写下这样的代码时
int main(int argc, char const *argv[])
{
mystring t1("1234");
const mystring t4=t1;
char *p=&t4[0];
*p='a';
cout<<t4<<endl;
return 0;
}
可见输出了a234,const对象被修改了,因为如果不对const版本的operator[]的返回值加const,那么,将返回一个字符的引用,这样就可以通过指针来修改数据,从而间接修改原来的const对象
当const版本的operator[]的返回值加上const后,返回的是一个const char的引用,此时用char 指针指向const char数据,
发生了下面的转化
const char t=data[0];
const char &rt=t;
char *p = &rt;
当编译器编译到第三行时,发现char *要指向一个const char *,所以报错,防止间接修改原来的const mystring对象
所以,const版本的operator[]的返回值要返回const数据的引用,防止数据被间接修改
第二个问题:能否用一个operator[]调用另外一个operator[]?
https://blog.youkuaiyun.com/Master_Cui/article/details/106885048
char & mystring::operator[](size_t n)
{
cout<<"operator[](size_t n)"<<endl;
return data_[n];
}
const char & mystring::operator[](size_t n) const
{
cout<<"operator[](size_t n) const"<<endl;
return data_[n];
}
代码很短,但是如果代码较长,能否用其中一个调用另一个,防止重复代码?
因为const成员函数不会修改成员,所以,不能用const成员你函数调用非const成员函数,所以,必须是非const版本调动const版本的operator[]
所以,会写下如下代码
char & mystring::operator[](size_t n)
{
cout<<"operator[](size_t n)"<<endl;
return operator[](n);
}
然而实际上并没有调用const版本的operator[],而是无限递归
所以直接调用不行,就需要想办法间接调用到const版本的operator[],因为const对象可以调用operator[],所以就需要构造一个const mystring,然后用构造出来的const对象来调用operator[],此时返回的是一个const char&,需要使用const_cast去除底层const,所以可以写下如下代码
char & mystring::operator[](size_t n)
{
cout<<"operator[](size_t n)"<<endl;
const mystring t=*this;
const char &rt=t.operator[](n);
return const_cast<char&>(rt);
}
int main(int argc, char const *argv[])
{
mystring c1="1234";
cout<<c1[1]<<endl;
}
然后并没有发现要找到的字符2,相反却出现了一个空格和一个析构函数的调用。这是因为构造的const对象是个局部对象,operator[]执行结束后,局部对象被释放,所以局部对象的引用也就无效了,所以没有打印出来字符2
修改代码如下,将局部对象变成引用绑定*this,这样函数退出后,*this不会被释放,所以引用也有效
char & mystring::operator[](size_t n)
{
cout<<"operator[](size_t n)"<<endl;
const mystring &t=*this;//变成引用
const char &rt=t.operator[](n);
return const_cast<char&>(rt);
}
将上述代码改为一行代码如下
char & mystring::operator[](size_t n)
{
cout<<"operator[](size_t n)"<<endl;
return const_cast<char&>(static_cast<const mystring &>(*this)[n]);
}
可见这回出现了字符2,并且使用非const版本的operator[]调用了const版本的operator[],只不过代码丑的一批
所以,如果const版本的operator[]实现并不复杂的话,非const版本的operator[]代码重复就重复吧,毕竟可读性好,否则再考虑这种丑的一批的转换式写法
参考
《Effective C++》
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出