C++语法·伍

个人总结,嗯你懂的。Q--Q       生活不就是这样起起 落落落洛洛洛落落落 

目录:

类和对象·中

C++是面向对象的语言,而面向对象语言有着三大特性:封装、继承、多态。还有其他特性,但不像它们三个这么重  。

默认成员函数

默认成员函数就是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。默认成员函数有6种,这里只着重说4种。

1.构造函数

构造函数有以下特点:

(1)函数名与类名相同。

(2)无返回值。(返回值什么都不需要给,也不需要写void,C++规定)

(3)对象实例化是系统会自动调用对应的构造函数,不需要手动调用。(自动调用真的好用,因为我们可能会有时候忘了对自定义类型进行初始化)

(4)构造函数可以函数重载。

(5)如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的构造函数。(这点有些歧义)

(6)无参构造函数、全缺省构造函数以及我们不写时编译器默认生成的构造函数,都叫默认构造函数。但是这三个只能同时存在一个。无参构造函数和全缺省构造函数虽然构成函数重载,但在调用时有歧义,(给一个无参的调用不知道调谁,这个在函数重载中说到过在C++语法·一中)。

注意只要是这三种函数都叫默认构造函数,总结来说只要是不传实参就可以调用的构造函数就叫默认构造函数。

理解:

构造函数的作用就是给类初始化。

对于内置类型(int、double等)这些成员变量,编译器自动生成的构造函数只会给它初始化随机值,一般来说是不符合我们的需求的。就是我们不写,编译器默认生成的构造函数的初始化是不确定的,所以我们对于内置类型的成员变量都要自己写默认构造函数。

而对于自定义类型(结构体、类等)的成员变量的初始化,编译器会自动调用该自定义类型成员的默认构造函数初始化,如果它没有,会报错。这里可以用初始化列表来解决,在之后的C++语法总结中会有。

注:内置类型就是语言提供的原生数据类型,如:int/char/double/指针等

自定义类型就是我们使用class/struct/enum/union等关键字自己定义的类型。

小结:只有一个类中全为自定义类型,且这些自定义类型全都有默认构造函数,这个类的初始化才不用手动写,而是默认构造的就可以。

它们都放在class Date这个类里,注意这两个不可以同时存在,使用时只能写一个。

全缺省使用时像上面这样,无参不需要使用,像下面这样,创建实例化对象就自动初始化了。

int main()
{
    Date d1;

    return 0;
}

2.析构函数

特点:

(1)析构函数名是在类名前加字符 ~ 。

(2)无参数无返回值,不需加void

(3)一个类只能有一个析构函数,若未显式定义,系统会自动生成默认的析构函数。

(4)对象生命周期结束时,系统会自动调用析构函数。(自动调用真的好用,因为我们可能会有时候忘了对自定义类型进行销毁)

(5)和构造函数类似,我们不写而自动生成的析构函数对内置类型成员不做处理,对自定义类型成员自动调用它的析构函数。

(6)还需注意的就是,我们显式写析构函数,对于自定义类型成员也是调它自己的析构函数。

理解:

析构函数不是完成对对象本身的销毁,比如局部对象是存在于栈帧的,函数结束是会自动销毁释放的,C++规定对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作。

资源指的是动态开辟的空间、文件指针等需要手动清理释放的。

默认调用析构函数的调用规则和构造函数的相似,在上面的理解部分

补充:对于函数体中创建的对象,析构的顺序是从最后创建的对象逆着到最先创建的对象

Date d4;
int main()
{
Date d1;
Date d2;
static Date d3;
return 0;
}

比如上面d3和d4生命周期都为全局,d1和d2生命周期都为局部,在main函数执行结束后,会先析构d2,然后是d1,之后程序结束销毁全局变量,d3和d4都是放在静态区的,而d4后创建,所以接着析构d4,最终析构d3。 析构顺序:d2-》d1-》d3-》d4   QRQ

3.拷贝构造函数

特点:

(1)拷贝构造函数是构造函数的一个重载。

(2)拷贝构造函数的第一个参数必须是类类型对象的引用,如果使用传值的方式编译器直接报错,因为语法逻辑上会引发无穷递归调用。拷贝构造也可以多个参数,但是第一个参数必须是类类型对象的引用,后面的参数必须为缺省参数。   

(3)C++规定自定义类型对象进行拷贝构造行为都必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。

   

d1传给d,相当于调用一次拷贝构造,然后拷贝构造函数Date(Date d)又要传参,又要进行拷贝构造,无限递归。

拷贝构造的使用就像上右边的图那样,意为用d2来初始化要初始化的d1。

但用引用的话,传参时不会进行拷贝构造,因为引用是取别名,不开空间,不需要拷贝,所以不用拷贝构造。

指针的话也不用拷贝,只是传地址,所以指针也可以,但指针不算拷贝构造,只算构造,而且没有引用方便简洁。

为了防止传过去的对象被修改,在引用前常加上const修饰。

(4)若未显式定义拷贝构造,编译器会自动生成拷贝构造函数。自动生成的拷贝构造函数对内置类型成员变量会完成值拷贝/浅拷贝(一个字节一个字节的拷贝),对自定义类型成员变量会调用它的拷贝构造函数。

(5)拷贝构造和构造不同,编译器是真的会自动生成的,只不过编译器只会浅拷贝/值拷贝,浅拷贝是

浅拷贝(值拷贝)

就是一个字节一个字节的拷贝。对于除指针外的内置类型来说是够用的。

But 有指针的浅拷贝会导致:

@析构时指向空间被free两次(直接报错,编译器不允许)因为free一次就还给操作系统了,操作系统可能会用这块空间,再free就不礼貌了。

@一个对象修改会影响另一个,因为拷贝后它们指向同一块空间。

深拷贝:

对象中的数据和指向的资源都要拷贝一份,资源比如堆区的空间,文件等资源。现在一般都是有指针和引用的需要深拷贝。

注意:

传值返回会调用一个临时对象调用拷贝构造,传值引用返回,返回的是返回对象的别名(引用),没有产生拷贝。但是如果返回对象是一个当前函数局部域的局部对象,函数结束就销毁了,那么使用引用返回是有问题的,这时的引用是野引用,相当于野指针。所以传引用返回是可以减少拷贝,但要注意使用场景,确保返回对象在当前函数结束后还在,才能用引用返回。

小结:一般来说,如果一个类显式的实现了释放资源的析构函数,那么就需要写拷贝构造函数了。
补充:

C语言正常进行浅拷贝,因为结构体里不能写函数,但也有办法实现深拷贝,就是比较复杂。

C++中可以直接用等号进行拷贝构造。

  这两个等价。

小知识:

1.对空指针解引用不会编译报错,而是运行崩溃。

2.取地址可以绕过const,不过不推荐使用。

3.运行速度:由快到慢——寄存器- 缓存 -内存-硬盘。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值