构造函数
构造函数是一个特殊的成员函数,名字与类名相同,无返回值,可以重载,创建对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次,其主要任务是初始化对象
使用构造函数
C++提供了显式调用和隐式调用两种使用构造函数来初始化对象的方式
注意:如果通过隐式调用默认构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
1 | class S { |
默认构造函数
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且只能有一个
若未显式定义构造函数,则编译器会自动生成一个无参的默认构造函数,主要作用是调用自定类型成员的默认构造,一旦用户显式定义编译器将不再生成
初始化列表
构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,在初始化列表中,而构造函数体内可以多次赋值
声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
1 | class A { |
单参构造
1 | class S { |
上述代码可读性不是很好,用explicit修饰构造函数,将会禁止单参构造函数的隐式转换
1 | explicit S(int s = 1) { |
C++11 成员初始化
C++11支持非静态成员变量在声明时进行初始化赋值,但是要注意这里不是初始化,这里是给声明的成员变量缺省值。即,如果初始化列表和声明的时候都有初始化参数,会优先使用初始化列表初始化
C++11 委派构造函数
通过委派其他构造函数,使多构造函数的类编写更容易
1 | // 委派构造函数将构造的任务委派给目标构造函数 |
构造函数不能同时“委派”和使用初始化列表
拷贝构造函数
本质是构造函数的一个重载形式,参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用
若未显示定义,编译器自动生成默认拷贝构造函数,默认的拷贝构造函数为浅拷贝
若显示定义拷贝构造,则编译器不会生成默认构造函数(拷贝构造是构造函数的重载)
析构函数
无参数无返回值,一个对象只有一个析构函数
若未显式定义,系统会自动生成默认的析构函数,对象在销毁时会自动调用析构函数,并对自定类型成员调用它的析构函数,完成类的一些资源清理工作
如果是在栈上创建多个对象,则最后创建的对象最先被删除,最先创建的对象最后被删除
注意:申请空间时候必须自己写析构函数
1 | class S { |
输出结果 ~S()
某些编译器可能输出两个 ~S()
C++标准允许编译器使用两种方式来执行S s = S();
- 第一种等价于
S s;
创建一个对象,执行一次析构 - 第二种会创造一个匿名临时对象,然后将匿名对象复制到s中,创建两个对象,执行两次析构
所以尽量使用S s;
这种隐式构造,通常效率更高
运算符重载
运算符重载是一种形式的C++多态
- 不能通过连接其他符号来创建新的操作符:比如operator@
- 重载操作符必须有一个类类型或者枚举类型的用户定义参数,防止用户为内置类型重载运算符。
- 必须遵守语法规则,如,不可将%重载成一个操作数。
- .* :: sizeof ?: . typeid const_cast dynamic_cast reinterpret_cast static_cast 不可重载
一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的浅拷贝
如果需要自己写赋值运算符重载,需要检查是否自己给自己赋值
1 | // 运算符重载演示 |
取地址及const取地址操作符重载
将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改
const对象不能调用非const成员函数
const成员函数内不能调用其它的非const成员函数
取地址及const取地址操作符重载一般不用重新定义,编译器默认会生成Type* operator&() { return this; }
const Type* operator&() const { return this; }
内联函数
编译时,编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率,但是占用更多内存。
- 当执行函数代码时间比处理函数调用机制时间长时,则节省的时间比例不高,不必声明为内联。当函数代码少,并且函数经常被调用,声明为内联可以提升程序运行效率
- inline对于编译器而言只是一个建议,编译器会自动优化,如果函数体内有循环/递归等,编译器优化时会忽略掉内联
- inline在类外定义时,只需在类实现部分中使用inline限定符,必须在每个使用它们的文件中都定义,防止链接错误,因为inline被展开,就没有函数地址了,链接就会找不到。所以直接将定义放在头文件中最简单
由于宏定义的缺点,在C++中我们可以采用内联函数和const替换宏的函数和常量定义