【C++】类成员初始化列表、三元运算符、运算符及其重载、箭头操作符

八、C++中的花式操作:构造函数初始化列表、三元运算符、运算符及其重载、箭头操作符

10、构造函数初始化列表
当我们编写一个类时,一般都要有一个构造函数对类中的成员(变量,有时也叫属性)进行初始化。
其实这个初始化的构造函数有两种写法,一种是前面示例中的赋值初始化,另一种就是现在我们要重点讲的初始化列表
也就是类成员初始化列表也是类成员初始化的一种方式。

(1)两种初始化方式:

(2)为什么要用列表初始化?
仅仅是代码风格吗?也有这方面的因素。试想,当你A处声明的变量非常多的时候,你赋值初始化就需要很多行代码,而列表初始化代码就简洁明了很多。
但更主要的原因是:

初始化e1时,类P之所以被初始了2次是因为,一次是在A处,一次是在B处。A处虽然是成员变量区,但并不意味着不会运行代码并创建对象!所以在A处就已经无参实例化了一个小p。然后代码运行到B处,在B处又创建了一个新P实例,然后把它赋值给小p,就是覆盖第一次实例的小p。
但是当我们使用列表初始化后,就避免了两次实例化P。所以以后能用列表初始化的尽量用列表初始化,不然会浪费性能。

11、三元运算符
所谓的三元运算符就是一个问号一个冒号。它实际上只是if..else语句的语法糖。

从上面的例子中可以看到三元运算符也就是仅仅让代码更简洁,至于是否更容易理解就仁者见仁智者见智了。
或者你从这个角度理解会更理解一些:if..else语句的本质就是赋值,如上例,本质就是给b赋值,但赋值是有条件的,所以写条件?成立就是10,不成立就是5。这其实就是一个条件赋值语句嘛。

说明:上图B处的声明语句string s1;其实是会构造一个空字符串对象,然后再用一个新对象覆盖这个空字符串。所以从技术上讲更慢。因为你先构造了一个临时字符串,然后又立即销毁它。而A处没有构建中间字符串的原因实际上是与返回值优化有关,是编译器的做了优化。

其实三元运算符还可以嵌套:

虽然嵌套的可读性差了一些,但是不用写很多if,代码简洁了不少。套娃无止境,还可以花式套,比如每个条件再加一些&&或者||等,但是一般还是别花式嵌套了吧,读代码的人很容易懵。

12、运算符及其重载
C++中运算符有很多,比如数学运算符加减乘除、逆向引用的箭头->也是运算符、+=、++、--、-=、&取址运算符、<<、>>、逗号、圆括号、方括号等等都是运算符。还有一些比如前面刚讲的new和delete也是运算符,还给大家展示了new和delete的底层定义函数,以及各自重载函数。不记得的同学回看 【C++】C++中的关键字:const、mutable、auto、new....-CSDN博客

这些运算符表面上看是一些符号,其实背后都是函数,都是调用了对应的函数去执行相应的功能。或者说,就是都写成多态(同名不同参)的样子,然后调用的时候根据参数进行重载。本部分我就介绍三个样例,给大家详细展示一下什么是运算符及其重载。

(1)向量运算符示例
运算符函数究竟怎么写,主要取决于你的应用场景,你想在什么场景下怎么使用。比如我想先能生成向量,然后生成的向量还可以做加法、乘法等之类的:

上述代码虽然实现了最初的简单需求,但是我们加法用Add,乘法用Multiply,是相当麻烦的,单词拼不对就很头疼。所以我打算改成+和*,这样不仅方便,代码还会更清晰可读。此时就该重载上场了:

这样就可以重载了。而且还可以像下面的风格来写:

其实,大家更习惯的写法是上面的第二种写法,就是先写符号函数,再写正常函数。写正常函数时用指针this,并使用符号函数。

(2)std::cout中使用的左移运算符
上面的例子中我们打印向量时非常麻烦,要一个个元素打印,那是因为<<运算符没有重载现在我们自己创造的这种Vec对象,下面我们再针对Vec这个类型,写一个<<重载函数: 

可见符号函数的语法是operator后面直接写你的符号,再后面是小括号里面放参数。通过这两个小例子,你现在就可以写任何你想的符号了,然后用符号替代函数。

(3)是否相等重载符
还是使用上面的例子,判断两个向量是否相等,返回bool值:

在写库时,运算符及其重载就会被经常写。

13、箭头操作符
本部分讨论C++中的箭头运算符(操作符),展示箭头运算符可以对结构体和类的指针做些什么?然后我们自己手写一个箭头操作符重载函数,展示箭头操作符的工作原理:

上面就是写了两个版本的箭头操作符重载函数,一个const版的一个非const版的,没有什么难度。可能稍微难一点的就是作用域指针的写法,不理解的可以参考 https://blog.csdn.net/friday1203/article/details/142023876?spm=1001.2014.3001.5501

重点是要说的是:如何使用箭头操作符,来获取内存中某个成员变量的偏移量 :

意思是我先写一个0,表示0号地址,也可以写成nullptr,然后我把这个地址转换成E*指针,然后让这个指针来访问类的数据成员x,就得到数据成员x的值(当然不允许我们看到值),然后我取x的内存地址,就得到x的偏移量,然后我再把这个偏移量转换成int类型,赋值给offset。

这是非常有用的,当你把数据序列化为一串字节流时,当你想要计算某些东西的偏移量时,当我们开始做图形编程、游戏引擎系列的时候,我们就会接触到这种代码,因为要处理字节流。

待续。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值