大纲:
1、指针和引用
2、类型转换
3、数组与多态的不可混用
4、默认构造函数
指针和引用
相同点:
间接地来使用对象
异同点:
指针可以指向空对象
引用必须指向非空对象,要求做初始化
可以改变指针指向,不可改变引用指向
抉择:
重载运算符、必须指向非空对象、不想改变其指向,使用引用;实际上,大多数的场景,我们需要改变指向,相对而言,指针可能适用的场景更多。
此外,关于使用指针、引用的效率问题:
由于引用不可指向空对象,因此可以免去测试指针为空步骤,所以使用引用的代码效率更高。
2、类型转换符
static_cast<Type>(expression)
const_cast<Type>(expression)
dynamic_cast<Type>(expression),沿着继承关系向下进行类型转换,对于指针转换失败,将返回空指针;对于引用转换失败,抛出异常。
3、数组与多态的不可混用
数组名称类似于引用,不可更改其指向。
数组源自于C,多态是C++概念,两者之间混用将带来bug。
数组连续存储,根据元素类型为其分配好空间后,在做初始化(调用对象的默认构造函数),将一个派生类对象的数组赋值给基类对象数组,可能发生对象切割(对象不完整),调用虚函数将发生不可知行为。
4、默认构造函数
功效:不利用任何外部数据就可以初始化类对象。对于一些类型来说,设置默认构造函数是合理的,另一些类型,提供默认构造函数是无意义的。按理来说,我们就按需来决定是否提供默认构造函数就好。
但是!如果类不提供默认构造函数,将会影响其使用范围。具体来说,存在以下几种限制场景:
- 无法生成该类型数组(由于要使用对象的默认构造函数)
解决方案:
用指针数组代替对象数组,此时数组存储的指针,将不存在调用对象的默认构造函数问题,显示调用元素构造函数生成对象,并将地址值赋值给数组的元素值。
使用placement new ,在分配的内存上可显示调用构造函数(避开默认构造函数限制),但是记得delete raw内存空间。
- 使用模板时,类作为类型参数,特别是如果标准库的模板可能调用类型参数的默认构造函数
- 虚基类
new和delete
new operator (new 操作符):
new operator 支持两种调用形式:
其一,new Type()
其二,new (raw)Type()
根据有没有指定raw地址,来决定调用何种operator new函数。调用operator new()获取raw内存地址,在其上初始化对象;传入指定地址,并调用placement new,在其地址上初始化对象。
程序员可直接调用operator new函数,此函数可重写或重载(加入新的参数),返回未初始化的空间。类似于C的malloc。
operator new声明:返回一个指向未初始化的内存的指针
placement new(another new操作符)
在已将分配好的内存空间(raw)上调用对象构造函数
operator new(new操作)
delete 操作符:先调用对象析构函数,在释放内存
delete 操作:仅释放内存
operator delete(void *buffer)
使用placement new操作符生成的对象,不可以使用delete operator 释放空间。不是配套的,new operator 生成的对象,可调用delete operator(void * buffer)释放内存。
使用new操作符来动态分配内置类型(用户定义类型)的数组,函数内调用operator new[]操作 分配合适大小的内存空间,调用指定个数的默认构造函数。
释放内置类型(自定义类型)数组,调用析构函数释放对象,在调用operator delete [] (buffer)释放内存空间
delete [] ps;
关于new /delete operator 、operator new/delete 函数,new /delete operator不可直接重写,功能不可变更,但可重写(重载)内存分配函数(operator new/placement new)。