Detailed explanation of C++ learning (memory model, object-oriented packaging, structure)

3 memory model

C++ divides memory into four regions during execution

Code area : store the binary code of the function body, managed by the operating system

Global area : store global variables static variables and constants

Stack area : automatically allocated and released by the compiler, storing function parameter values, local variables, etc.

Heap area : allocated and released by the programmer, if the programmer does not release it, it will be reclaimed by the operating system after the program ends

The significance of partitioning : giving different life cycles to the data stored in different areas, giving us more flexible programming

3.1 code area

After the program is compiled, the exe executable program is generated. Before the program is executed, it is divided into two areas: the code area and the global area

Code area: Stores the machine instructions executed by the CPU, which are shared. For frequently executed programs, only one copy needs to be saved in the memory. Read-only prevents a program from accidentally modifying its instructions.

3.2 Global zone

Global variables, static variables, and constants (const-modified global constants and string constants) are stored. The data in this area is released by the operating system after the program ends.

3.3 stack area

It is automatically allocated and released by the compiler to store function parameter values, local variables, etc.

Note: Do not return the address of the local variable, because the data in the stack area is automatically released after the function is executed

You can see that the return address in the method will be printed out for the first time, but not the second time. This is because the compiler made a reservation the first time.

Here I executed the same code again and the output is the address twice:

Very confused, and finally asked GPT, his answer:

3.4 Heap area

Allocated and freed by the programmer, and reclaimed by the operating system at the end of the program if the programmer does not release

In C++, new is mainly used to open up memory in the heap area.

The essence of the pointer is also a local variable, which is also placed on the stack. The data saved by the pointer is placed in the heap area

Delete releases the data in the heap memory. If you access it after release, it is an illegal operation and an error will be reported.

4 object-oriented

4.1 Advanced applications of functions

4.1.1 Default parameters of functions

If we pass in the data ourselves, we will use the passed in data, and if the user does not pass in a value, we will use the default parameters.

Precautions:

1 If there is a default parameter at a position, then there must be a default value from left to right from this position

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 通过类名访问

静态成员函数:

所有对象共享一个函数

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

Guess you like

Origin blog.csdn.net/m0_56366502/article/details/129731080