C++学习(内存模型、面向对象封装、构造)详解

3内存模型

C++在执行期间将内存分为四个区域

代码区:存放函数体的二进制代码,由操作系统进行管理

全局区:存放全局变量静态变量以及常量

栈区:由编译器自动分配释放,存放函数的参数值、局部变量等

堆区:由程序员分配和释放,若程序员不释放,程序结束后由操作系统回收

分区的意义:给不同的区域存放的数据赋予不同的生命周期,给我们更大的灵活编程

3.1代码区

程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域:代码区和全局区

代码区:存放的是CPU执行的机器指令,共享的,对于频繁执行的程序只需要在内存中保存一份即可。只读的防止程序意外的修改了它的指令。

3.2全局区

存放了全局变量、静态变量、常量(const修饰的全局常量和字符串常量)。该区域的数据在程序结束后由操作系统释放。

3.3栈区

由编译器自动分配和释放,存放函数的参数值、局部变量等。

注意:不要返回局部变量的地址,因为栈区的数据在函数执行完之后自动释放

可以看到在方法中返回地址在第一次会打印出来,第二次就不会打印了。这是因为在第一次的时候编译器做了保留。

这里我又执行了一次一样的代码输出的两次都是地址:

很迷茫,最后问了GPT ,他的回答:

3.4堆区

由程序员分配和释放,程序员不释放程序结束时由操作系统回收

在C++中主要利用new在堆区开辟内存。

指针的本质也是局部变量,也是放在栈上,指针保存的数据是放在了堆区

Delete释放堆内存的数据,如果释放后再访问就是非法操作 会报错

4面向对象

4.1函数的高级应用

4.1.1函数的默认参数

如果我们自己传入数据,就用传入的数据,如果用户不传值,就用默认参数。

注意事项:

1 如果一个位置开始有了默认参数,那么从这个位置往后从左到右都必须有默认值

2 函数的声明和实现只能有一个有默认参数。

4.1.2函数的占位参数

C++的函数形参列表中可以有一个占位参数,用来做占位,调用函数时必须填补该位置。

使用:返回值类型 函数名字(数据类型)

占位符也可以有默认值

4.1.3函数重载

函数名字可以相同,提高复用性。

函数重载的条件:

1 同一个作用域下

2 函数名相同

3 函数的形参类型个数顺序不同

注意:函数的返回值不可以作为函数重载的条件

4.1.4函数重载的注意事项

引用作为重载条件

函数重载避免出现默认参数

4.2封装

4.2.1封装的意义

将属性和行为封装成一个整体,表现生活中的事物,将属性和行为加以权限控制

4.2.2访问权限

public:公共权限,成员类内和外都能访问

protected:保护权限,类内能访问 类外不可以访问,子类可以访问父类的保护成员

private:私有权限,类内能访问 类外不可以访问,子类不可以访问父类的保护成员

私有成员和保护成员在类外是访问不到的,可以用get、set方法进行访问。

4.2.3struct和class

二者都可以修饰一个类。

struct默认的访问权限是公共,class默认的权限是私有的

4.3对象的初始化和清理

4.3.1构造和析构

构造函数:主要在创建对象时给对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。

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

2无返回值也不写void

3构造函数可以有参数,因此可以发生重载

4程序在初始化的时候会自动调用构造,无需手动调用,而且只会调用一次

析构函数:在于对象销毁前系统自动调用,执行一些清理工作。

1 函数名与类名同名 ~函数名()

2无返回值也不写void

3构造函数可以有参数,因此可以发生重载

4 程序在对象销毁前会自动调用析构,无需手动调用,而且只会调用一次

4.3.2 构造函数的分类以及调用

分类方式:

有参构造和无参构造

普通构造和拷贝构造

调用方式:

1 括号法

注意:调用默认构造函数时不要加()

2 显示法

3 隐式转换法

4.3.3拷贝构造函数的调用时机

1使用一个已经创建完的对象来初始化一个新对象

2 值传递的方式给函数参数传值

3 以值方式返回局部对象,可以看到第一次调用的地址和第二次的不同,不是同一个对象。

4.3.4构造函数的调用规则

默认情况,C++会给一个类至少添加三个函数:

1 默认构造函数

2 默认析构函数

3 默认拷贝构造函数

构造函数的调用规则如下:

如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造。

如果用户自定义拷贝构造,C++不会再提供其他构造函数。

4.3.5深拷贝和浅拷贝

浅拷贝:简单的赋值操作

深拷贝:在堆区重新申请空间,进行拷贝操作

如果利用编译器提供的拷贝构造函数,会做浅拷贝操作。

下面是一段代码,创建一个对象放在了堆内存里,然后在析构函数里释放。

这样写代码会出现问题:

根据先进后出的原则,会先释放s1,再释放s,但是s和s1会指向同一个堆内存,会导致同一块区域的堆内存释放两次,堆内存重复释放就会报错。

解决浅拷贝的问题就是深拷贝。

深拷贝的实现:创建一块新的内存地址就不会报错了。

如果属性有在堆区开辟的,一定要自己提供一个深拷贝函数,防止浅拷贝带来的问题。

4.3.6初始化列表

构造函数用来给属性进行初始化的操作,初始化列表也能用来给属性进行初始化。

语法:构造函数():属性1(值1),属性2(值2){ }

进行值的传入:

4.3.7 类对象作为类成员

class A{ };

class B {

A a;

};

C++中一个类的成员可以是另一个类的对象,这中成员被称为对象成员。在上面的例子中,B中有成员A ,A就是对象成员。

此时创建一个B对象,会先初始化A的构造:

总结:当其他类对象作为本类成员时,构造的时候先构造类对象,再构造自身,析构的顺序相反。

4.3.8静态成员

就是在成员函数或者变量前面加上static

静态成员变量:

所有对象共享同一份数据

在编译阶段分配内存,在全局区

类内声明,类外初始化

静态成员变量有两种访问方式:

1 通过对象访问

2 通过类名访问

静态成员函数:

所有对象共享一个函数

静态成员函数只能访问静态成员变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值