C++学習の詳しい解説(メモリモデル、オブジェクト指向パッケージング、構造)

3メモリモデル

C++ は実行中にメモリを 4 つの領域に分割します

コード領域: オペレーティングシステムによって管理される関数本体のバイナリコードを格納します

グローバル領域:グローバル変数、静的変数、定数を格納

スタック領域:コンパイラによって自動的に確保・解放され、関数のパラメータ値やローカル変数などが格納されます。

ヒープ領域: プログラマによって割り当ておよび解放されます。プログラマが解放しない場合、プログラム終了後にオペレーティング システムによって再利用されます。

パーティショニングの重要性: 異なる領域に保存されたデータに異なるライフサイクルを与え、より柔軟なプログラミングを可能にする

3.1 コード領域

プログラムがコンパイルされると、exe実行可能プログラムが生成されますが、プログラムが実行される前は、コード領域とグローバル領域の2つの領域に分割されます。

コード領域:CPUが実行する機械命令を共有して格納する領域で、頻繁に実行するプログラムは1部メモリに保存するだけで済みます。読み取り専用は、プログラムがその命令を誤って変更することを防ぎます。

3.2 グローバルゾーン

グローバル変数、静的変数、および定数(const 修飾されたグローバル定数および文字列定数)が格納されます。この領域のデータは、プログラム終了後にオペレーティング システムによって解放されます。

3.3 スタック領域

関数パラメータ値やローカル変数などを保存するために、コンパイラによって自動的に割り当ておよび解放されます。

注: スタック領域のデータは関数実行後に自動的に解放されるため、ローカル変数のアドレスは返さないでください。

メソッド内の戻りアドレスが初めて出力されますが、2 回目は出力されないことがわかります。これは、コンパイラが最初に予約を行ったためです。

ここで同じコードを再度実行すると、アドレスが 2 回出力されます。

非常に混乱し、最終的に GPT に尋ねたところ、彼の答えは次のとおりでした。

3.4 ヒープ領域

プログラマによって割り当ておよび解放され、プログラマが解放しない場合はプログラムの終了時にオペレーティング システムによって再利用されます。

C++ では、new は主にヒープ領域のメモリを解放するために使用されます。

ポインタの本質もローカル変数であり、これもスタック上に置かれ、ポインタによって保存されたデータはヒープ領域に置かれます。

削除はヒープメモリ上のデータを解放しますが、解放後にアクセスすると不正な操作となりエラーが報告されます。

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

静态成员函数:

所有对象共享一个函数

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

おすすめ

転載: blog.csdn.net/m0_56366502/article/details/129731080