目录
实现类成员函数
- 定义成员函数时,使用作用域解析运算符(::)来表示函数所属的类。
- 类方法可以方位类的 private 组件。
- 同一个类的其他成员函数不必使用作用域解析运算符,就可以使用该类下的方法。
内联方法
- 其定义位于类声明中的函数都将自动成为内联函数。(定义是有函数体)
- 也可在类声明外定义成员函数,只需在定义函数前加 inline 限定符。
- 内联函数在编译时,会将此内联函数代码直接编译到调用函数之处。减少了一次函数调用时的跳转、数据压栈等操作。所以相比调用函数,内联函数的执行效率要相对高点。不过也正因为如此,所以最终生成的程序文件比较大。
- 内联函数要求在每个使用它们的文件中都对其进行定义。
构造函数
- 名称与类名相同,没有返回值,没有声明类型。
- 默认构造函数:
在未提供显式初始值时,用来创建对象的构造函数。
当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。但如果为类定义了构造函数,同样必须提供默认构造函数。 - 定义默认构造函数的两种方法:
1.给已有构造函数的所有参数提供默认值
2.没有任何参数
复制构造函数
用于将一个对象复制到新创建的对象中,即用于初始化过程,而不是常规的赋值过程,它接受一个指向类对象的常量引用作为参数:
Class_name(const Class_name &);
何时调用:
- 新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用;
每当程序生成了对象副本时,编译器都会使用复制构造函数,即,当函数按值传递对象或函数返回对象时,都会使用复制构造函数; - 注意:由于按值传递对象会调用复制构造函数,因此应该按引用传递对象,这样可以节省调用构造函数的时间以及存储新对象的空间。
注意:
- 如果类中包含了使用 new 初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这被称为深度复制。
- 如果需要使用复制构造函数但没有定义,编译器将自动生成一个
深度复制:
复制字符串并将副本的地址赋给 str 成员,而不仅仅复制字符串的地址,这样每个对象都有自己的字符串,而不是引用另一个对象的字符串。调用析构函数时都将释放不同的字符串,而不会去释放已经被释放的字符串,从而发生错误。
析构函数
-
名称与类名相同,类名前加上 ~,没有返回值,没有声明类型,每个类只有一个。
-
如果构造函数使用了 new ,则必须提供使用 delete 的析构函数。
-
delete(无论带不带中括号)都可以用于空指针
-
对不是使用 new 初始化的指针使用 delete 时,结果将是不确定的。
-
由编译器决定什么时候调用:
如果创建的是静态存储类对象,则其析构函数将在程序结束时自动被调用;
如果创建的是自动存储类对象,则析构函数在程序执行完代码块时(该对象是在其中定义的)自动被调用;
如果对象是通过 new 创建的,则它将驻留在栈内存或自由存储区中,当使用 delete 来释放内存时,其析构函数将自动被调用。
this 指针
this 指针被设置为调用对象的地址,*this 是该对象的别名。
注意
Stock stock2 = Stock("Boffo Objects",2,2.0);
stock1 = Stock("Nifty Foods",10,20.0);
这两条语句有根本性差别:第一条语句是初始化,它可能会创建临时对象(也可能不会);第二条语句是赋值,总会在赋值前创建一个临时对象。初始化效率更高。
const 成员函数
只要类方法不修改调用对象,就应将其声明为 const ,如,函数定义为void Stock::show() const
声明时void show() const;
static 类成员函数
- 不能通过对象调用静态成员函数,静态成员函数不能使用 this 指针。
- 如果静态成员函数实在公有部分声明的,则可以使用类名和作用域解析运算符来调用它。
- 静态成员函数只能使用静态数据成员。
对象数组
初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应的元素中。因此,要创建类对象数组,这个类必须有默认构造函数。
作用域为类的常量
class Bakery
{
private:
const int Months = 12;
double costs[Months];
...
这是行不通的!
可以使用下面两种方法:
- 在类中声明一个枚举。但声明的枚举不会创建类数据成员,即所有对象中都不包含枚举。
- 使用关键字 static 。
重载
运算符重载
- 格式:
operatorop()
- op 是有效的C++运算符,如 operator+() 重载 + 运算符。
- 重载后若运算符两侧是不同类型的对象,则左侧操作数是调用对象。
友元
友元函数
- 类的友元函数是非成员函数,它的访问权限与成员函数相同。
- 关键字
friend
,并将其原型放在类声明中,但友元函数不是成员函数,不能使用成员运算符(.)来调用。 - 编写函数定义时,不要使用 Time:: 限定符,不要在定义中使用 friend 。
explicit
-
C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色。 1 是个构造器 ,2 是个默认且隐含的类型转换操作符。
所以, 有时候在我们写下如 AAA = XXX, 这样的代码, 且恰好XXX的类型正好是AAA单参 数构造器的参数类型(或者除了第一个参数外其余参数都有默认值的多参构造函数), 这时候编译器就自动调用这个构造器, 创建一个AAA的对象。
这样看起来好象很酷, 很方便。 但在某些情况下, 却违背了我们(程序员)的本意。 这时候就要在这个构造器前面加上explicit修饰, 指定这个构造器只能被明确的调用/使用, 不能作为类型转换操作符被隐含的使用。
转换函数
从类类型转换到某种类型,是用户定义的强制类型转换。
operator typeName();
typename 为要转换的类型
- 转换函数必须是类方法
- 转换函数不能指定返回类型
- 转换函数没有参数
静态类成员变量
- 无论创建了多少个对象,程序只创建一个静态类变量副本,即类的所有对象共享同一个静态成员。
- 不能在类声明中初始化静态成员变量,而应在类方法的文件中初始化。(这是因为类声明位于头文件中,程序可能将头文件包含在其他几个文件中,如果在头文件中进行初始化,将出现多个初始化语句副本,从而引发错误)
- 如果静态成员是 const 整数类型或枚举型,则可以在类声明中初始化。