运算符重载
在重载流插入运算符中,如果将重载的函数放在类内,则会导致运算符方向相反。
这是什么原因呢?
运算符重载注意事项
- 在运算符重载中,双目运算符的第一个参数一定要是运算符的左操作数,第二个参数一定要是右操作数,运算符重载无法改变运算符的操作数个数。
- 在运算符重载中,若重载多个运算符,则要注意运算符的复用,如可以复用+= 重载 +,在复用过程中,要注意复用顺序不同可能导致不同的时间花费(主要是进行的构造函数的次数不同)。
- 在重载右不同含义的单目运算符,如++,–,前置++,–没有参数,后置++,–有一个int类型的参数(C++规定)。
- (),[],=运算符重载函数只能作为类的成员函数,因为这种运算符的左操作数是有限制的。
一些不能重载的运算符
C++存在一些不能重载的运算符。
1.作用域操作符: ::
2.条件操作符: ?:
3.点操作符: .
4.指向成员操作的指针操作符:->* , . *
const成员函数
在成员函数后加const,代表成员函数隐式传递的this指针被const修饰。
若下图print函数不加const,则会报错,因为权限扩大了。
初始化列表
初始化列表是用来初始化成员变量的,在C++中,栈帧开辟后会将栈帧初始化为随机值,所以在对象定义的时候,实际上已经被初始化为随机值了,这就导致如引用,被const修饰的成员,以及自定义类型,无法在构造函数修改(构造函数对成员进行的操作是赋值,同时无法访问其他类),所以需要引入初始化列表进行初始化,解决这个问题。
同时,成员的缺省值所缺省的就是初始化列表,如果某个成员已被初始化列表初始化,则不需要走缺省值。
初始化列表也有缺陷,如要开辟数组,则初始化列表就无法做到,所以最优的使用方法是初始化列表和构造函数一起使用,去长补短。
要注意,初始化列表初始化的顺序和成员声明顺序相同,所以在写初始化列表时,最好按声明顺序写初始化列表。
复制列表初始化自定义类型
在自定义类型初始化的时候,我们可以使用一个或多个内置类型进行初始化,前提是该自定义类型要有与参数对于的构造函数。
类型转换原理
任何类型转换,在底层都是开辟一块临时空间,用在暂存被转换的类型,然后在将临时空间赋值给变量。
将内置类型隐式转换成自定义类型,在1过程,调用自定义类型的构造函数,在2过程,调用自定义类型的拷贝构造。
关键字explicit
关键字explicit用来修饰构造函数,被修饰的构造函数无法通过复制列表的方式来调用构造函数。
模板
有些函数在使用的时候,内部逻辑是一样的,但是所传递的参数的类型是不一样的,对于这样的函数,C语言实现通常要写很多个不同的类型,但是引入模板后,就可以只写一份,大大提高了程序员的开发效率。
声明
模板的声明要使用template,typename/class关键字,如图。
声明是语法 template<typename/class T1, typename/class T2 …>,T1,T2是形参可以是任意字母。
在我们使用的时候,可以模板进行实例化,对于部分函数模板来说,其可以通过参数的类型来推到T的类型,从而进行隐式实例化,但作为类模板来说,就必须显示实例化。
模板的注意事项
关于模板类,模板函数和类模板,函数模板的区别。
1.类模板是模板,而模板类是类模板实例化后的类的名字,类模板实例化后依旧是抽象的。
2.函数模板是模板,而模板函数是函数模板实例化后的函数的名字。
综上,模板是不占用空间的,只有实例化后(类模板在实例化后)才会占用空间。
类模板的类目不是类的类型,类名<类型> 才是类的类型。
模板类的成员函数声明和定义不能分文件写,并且模板类的成员函数声明定义分离要遵守以下规则。