C++编程进阶1(对于单纯的常量,用const替换#define、operator[]与const)

一、对于单纯的常量,用const替换#define;用内联函数替换宏函数

如果想表示一个常量,请使用const而不是#define,因为#define在预编译期被简单的替换,没有类型检查。而const变量会被编译,编译期间会进行类型检查,更加安全可靠。除了类型检查之外,由于#define只是简单的将宏名替换,所以会导致生成的目标代码更大,而const就不会

 

二、operator[]与const

在博客https://blog.csdn.net/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.csdn.net/Master_Cui/article/details/106885048

目前两个版本的operator[]的实现如下

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++》

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值