C++ オブジェクト指向の最も基本的な概要

補足:メモリパーティションモデル

スタック: ローカル変数と関数パラメータを保存するためにコンパイラによって割り当ておよび回復されます。
ヒープ: プログラマによって管理され、new malloc delete free によって手動で割り当ておよび回復する必要があります。スペースは大きいですが、メモリ リークや空きフラグメントが発生する可能性があります。
グローバル/静的記憶領域: 初期化済みと未初期化の 2 つの隣接する領域に分割され、初期化済みと未初期化のグローバル変数および静的変数が格納されます。
定数ストレージ領域: 定数を保存します。通常は変更できません。
コード領域:プログラムのバイナリコードを格納します。

C++ プログラムを実行すると、メモリの大まかな方向は 4 つの領域に分割されます。
コード領域:オペレーティング システムによって管理される関数本体のバイナリ コードが格納されます。 グローバル
領域:グローバル変数と静的変数が格納され、定数
スタック領域:自動的に格納されます。コンパイラによって割り当てられます。解放、関数パラメータ値、ローカル変数などを保存します。
ヒープ領域:プログラマによって割り当ておよび解放されます。プログラマが解放しない場合、プログラムの終了時にオペレーティング システムによって回復されます。

メモリの 4 つの領域の意味:
データは異なる領域に保存され、異なるライフサイクルが与えられ、柔軟性が向上します プログラミングの
概要:
C++ は、プログラムが実行される前にグローバル領域とコード領域に分割されます。
コード領域は共有されるという特徴があります。
グローバル変数、静的変数、および定数を格納します。const
修飾されたグローバル定数および文字列定数を定数領域に格納します。

関数のオーバーロード

関数: 再利用性を高めるために、関数名を同じにすることができます。コンパイル時のポリモーフィズムを体現する
関数のオーバーロードは次の条件を満たします:
同じスコープ (同じクラス内の同じ名前の関数、オーバーロードされる) で、
関数名が同じ
、関数のパラメーターの型が異なる、または番号が異なる、または順序が違います(戻り値の型は気にしないでください)

1. クラスとオブジェクト

1 オブジェクト指向とは何かを簡単に説明します

オブジェクト指向とは、あらゆるものをオブジェクトとみなし、そのオブジェクトが持つ属性変数や、その属性変数を操作する関数をクラスにパッケージ化して表現する考え方です。

プロセス指向とオブジェクト指向の違い プロセス指向
:ビジネスロジックに従って上から下へコードを書く
オブジェクト指向:データと関数をバインドしてカプセル化し、プログラムの開発を高速化し、プログラムの書き換えプロセスを削減する繰り返されるコード。
たとえば、
Windows ソケット クラス、ウィンドウ クラス、
点群クラス PointCloud、opencv
cv::Point2i、cv::Point2f、cv::Point2d、cv::Point3i、cv::Point3f、cv::Point3d
オブジェクトの 3 つの主要な特性-指向性は、カプセル化、継承、ポリモーフィズムです。

カプセル化: データとデータを操作するメソッドを有機的に結合し、オブジェクトのプロパティと実装の詳細を非表示にし、オブジェクトと対話するインターフェイスのみを公開します。カプセル化は本質的に一種の管理であり、他の人に見られたくない場合は、protected/private を使用してメンバーをカプセル化します。一部の公開メンバー機能を公開し、メンバーが適切にアクセスできるようにします。

継承:既存のクラスのすべてのデータ メンバー関数と関数メンバー関数を使用し、元のクラスを書き直すことなくこれらの関数を拡張できます。

ポリモーフィズム: 親型のポインターを使用してそのサブクラスのインスタンスを指し、親クラスのポインターを通じて実際のサブクラスのメンバー関数を呼び出します。ポリモーフィズムを実現するには、書き換えとオーバーロードという 2 つの方法があります。

C++ は考えるすべてはオブジェクトです、オブジェクトのプロパティと動作

//圆周率
# PI 3.14
const double PI = 3.14;
//1、封装的意义
//将属性和行为作为一个整体,用来表现生活中的事物
//封装一个圆类,求圆的周长
//class代表设计一个类,后面跟着的是类名
class Circle
{
    
    
//访问权限,默认 私有的
//属性
int m_r;//半径
//行为
//获取到圆的周长
public:
double calculateZC()
{
    
    
//2 * pi
* r
//获取圆的周长
return
2 * PI * m_r;
}
};
int main() {
    
    
//通过圆类,创建圆的对象
// c1就是一个具体的圆
Circle c1;
c1.m_r = 10; //给圆对象的半径 进行赋值操作
//2 * pi * 10 = = 62.8
cout << "圆的周长为: " << c1.calculateZC() << endl;system("pause");
return 0;
}

コンストラクターおよびデストラクター オブジェクトの初期化とクリーンアップ

コンストラクター: 主な機能は、オブジェクトの作成時にオブジェクトのメンバー プロパティに値を割り当てることです。コンストラクターは、手動で呼び出すことなく、コンパイラーによって自動的に呼び出されます

デストラクター: 主な機能は、オブジェクトが破棄される前にシステムが自動的に呼び出して、クリーニング作業を実行することです。

C++ はコンストラクターとデストラクターを使用して上記の問題を解決し、これら 2 つの関数はコンパイラーによって自動的に呼び出され、オブジェクトの初期化とクリーンアップを完了します。
オブジェクトの初期化とクリーンアップはコンパイラによって強制されるものであるため、構築と破棄を提供しない場合はコンパイラが実行します。

コンパイラーによって提供されるコンストラクターとデストラクターは空の実装です。

空のクラス A sizeof(A) は、型 A のオブジェクトをインスタンス化します。一意のアドレスを決定するために、
通常のメンバー関数またはデストラクターのみを含む 1 バイトを返し、コンストラクターで 1 を返します。

クラス内の通常のメンバー関数は、sizeof() の統計には関与しません。デストラクタやコンストラクタなどのメンバ関数は sizeof とは関係がありませんが、通常のメンバ関数がクラス本体に対しての sizeof に対して、sizeof はインスタンス用であるため、理解するのは難しくありません。クラスのメンバ関数は、複数のインスタンスでも共有されます。同じ関数ポインターであるため、当然のことながら、インスタンスのサイズに起因するものではありません。

ここに画像の説明を挿入

空のクラスは構築と破棄を提供しません。コンパイラーが提供するコンストラクターとデストラクターは空の実装です。

デフォルトでは、C++ コンパイラはクラス 1 に少なくとも 3 つの関数を追加します
デフォルトのコンストラクター (パラメーターなし、関数本体は空)
2. デフォルトのデストラクター (パラメーターなし、関数本体は空)
3. デフォルトのコピー コンストラクター。プロパティの値をコピーし
、代入演算子も提供します。

コンストラクターを呼び出すための規則は次のとおりです。
ユーザーがパラメーター化されたコンストラクターを定義した場合、C++ はデフォルトの引数なしのコンストラクターを提供しなくなりましたが、デフォルトのコピー コンストラクターを提供します ユーザーがコピー コンストラクターを定義した場合、C++ は他のコンストラクターを提供しませ

C++ の空のクラスでデフォルトで生成されるクラス メンバー関数はどれですか

C++ コンパイラはクラスに少なくとも 6 つの関数を追加します

1. デフォルトのコンストラクター (パラメーターなし、関数本体は空)
2. デフォルトのデストラクター (パラメーターなし、関数本体は空)
3. デフォルトのコピー コンストラクター、属性の値をコピーします (浅いコピー)

4. 代入演算子オーバーロード関数、属性の値コピー(浅いコピー)
5. 値演算子オーバーロード関数
6. const 値演算子オーバーロード関数

クラス内にヒープ領域を指す属性 (クラス内のポインター メンバーなど) がある場合、代入操作を実行するときに深いコピーと浅いコピーの問題も発生します。

class Empty
{
    
    
public:
Empty(); // 缺省构造函数//
Empty( const Empty& ); // 拷贝构造函数//
~Empty(); // 析构函数//
Empty& operator=( const Empty& ); // 赋值运算符//
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};

これらの関数を使用する必要がある場合にのみ、コンパイラがそれらの関数を定義しますか?
ここに画像の説明を挿入

深いコピーと浅いコピー

*典型的な例では、クラスにはポインター メンバー int p が含まれています。
これは、必要に応じて手動で記述する必要があるコピー コンストラクターです。

浅いコピー: 単純な代入コピー操作。ポインタ変数 p のコピーをコピーするだけでは
、同じポインタが 2 回解放される可能性があります
ディープ コピー: ヒープ領域に領域を再適用し、ポインタ p が指すオブジェクトをコピーします。

https://blog.csdn.net/wue1206/article/details/81138097

class Test
{
    
    
private:
    int* p;
public:
    Test(int x)
    {
    
    
        this->p=new int(x);
        cout << "对象被创建" << endl;
    }
    ~Test()
    {
    
    
        if (p != NULL)
        {
    
    
            delete p;
        }
        cout << "对象被释放" << endl;
    }
    int getX() {
    
     return *p; }
    //深拷贝(拷贝构造函数)
    Test(const Test& a)
    {
    
    
        this->p = new int(*a.p);
        cout << "对象被创建" << endl;
    }
    //浅拷贝(拷贝构造函数)
    //Test(const Test& a)
    //{
    
    
    //  this->p = a.p;
    //  cout << "对象被创建" << endl;
    //}
};

int main()
{
    
    
    Test a(10);
    //我们手动的写拷贝构造函数,C++编译器会调用我们手动写的
    Test b = a;
    return 0;
}

初期化リスト

Person p(1, 2, 3);
p.PrintPerson();

クラス オブジェクトは、構築と破棄の順序を調べるためのクラス メンバーとして使用されます。

https://blog.csdn.net/weixin_39731083/article/details/81903997
2. コンストラクタの呼び出し順序
基底クラスのコンストラクタ、オブジェクトメンバのコンストラクタ、派生クラス自身のコンストラクタ

  1. デストラクターの呼び出し順序は、
    派生クラス自体のデストラクター、オブジェクト メンバーのデストラクター、基本クラスのデストラクターの順です (構築の順序はまったく逆です)。

4. 特殊なケース
ローカル オブジェクト。プログラム ブロックの終了時に破棄されます。

静的オブジェクト。それが定義されているファイルの最後に破棄されます。

グローバル オブジェクト。プログラムの終了時に破棄されます。

継承オブジェクトでは、最初に派生クラスを破棄し、次に親クラスを破棄します。

オブジェクト メンバー。最初にクラス オブジェクトを破棄し、次にオブジェクト メンバーを破棄します。

4.2.8 静的メンバー

静的メンバーは、メンバー変数とメンバー関数の前にキーワード static を追加するもので、静的メンバーと呼ばれます

//静态成员变量两种访问方式
//1、通过对象
Person p1;
p1.m_A = 100;
cout << "p1.m_A = " << p1.m_A << endl;
Person p2;
p2.m_A = 200;
cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据
cout << "p2.m_A = " << p2.m_A << endl;
//2、通过类名
cout << "m_A = " << Person::m_A << endl;
//cout << "m_B = " << Person::m_B << endl; //私有权限访问不到

静的メンバーは次のように分割されます。
静的メンバー変数
すべてのオブジェクトは同じデータを共有します。
メモリはコンパイル段階で割り当てられます。クラス内の宣言、静的メンバー関数は
クラス外で初期化されます。 すべてのオブジェクトは同じ関数を共有し、静的関数を呼び出すことによってのみアクセスできます。クラス名またはオブジェクト名を使用したメンバー関数 静的メンバー変数および静的メンバー関数はオブジェクト自体を返すことはできません


4.3 C++ オブジェクト モデルとこのポインタ C++ では、クラス内のメンバ変数とメンバ関数は別々に格納されます。

C++ではクラス内のメンバ変数とメンバ関数は別々に格納されます
(メンバ関数のコードはコード領域にあるはず??)

只有非静态成员变量才属于类的对象的内存上,占用对象的内存空间

このポインタの概念

C++ ではメンバー変数とメンバー関数は別々に格納されるため、
各非静的メンバー関数は関数インスタンスを生成するだけです。つまり、同じ型の複数のオブジェクトが 1 つのコードを共有することになるため、問題は次のとおりです
このコードとそのコードを区別してください。それ自体を呼び出すオブジェクトについてはどうでしょうか? このポインタ
このポインタ 非静的メンバー関数は、このポインタを使用して、どのオブジェクトが自分自身を呼び出しているかを区別します。
this ポインタは、呼び出されたメンバ関数が属するオブジェクトを指します。this
ポインタは、各非静的メンバ関数に
暗黙的に含まれるポインタです。

明示的な this ポインタの目的:
1. 仮パラメータとメンバ変数が同じ名前である場合、this ポインタを使用して区別できます。
2.クラスの非静的メンバ関数でオブジェクト自体を返すには、次のようにします。 return *this を使用できます

class Person
{
    
    
public:
Person(int age)
{
    
    
//1、当形参和成员变量同名时,可用this指针来区分
this->age = age;
}
Person& PersonAddPerson(Person p)
{
    
    
this->age += p.age;
//返回对象本身
return *this;
}
int age;
};
void test01()
{
    
    
	Person p1(10);
	cout << "p1.age = " << p1.age << endl;
	Person p2(10);
	p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);
	cout << "p2.age = " << p2.age << endl;
}
int main() {
    
    
	test01();
	system("pause");
	return 0;
}

4.3.4 const 変更メンバー関数

const を置く場所がなく、関数の前の位置は static/inline で占められているため、関数の後ろにしか配置できません O(∩_∩)O はは~

定数関数:
メンバー関数の後に const を追加した後、この関数を定数関数と呼びます。
定数関数ではメンバー属性を変更できません。
メンバー属性の宣言時にキーワード mutable を追加した後でも、
定数オブジェクトは変更できます定数関数内:
オブジェクト宣言の前に const を追加します オブジェクトは定数オブジェクトと呼ばれます
定数オブジェクトは定数関数のみを呼び出すことができます。

class Person {
    
    
public:
	Person() {
    
    
		m_A = 0;
		m_B = 0;
	}

	//this指针的本质是一个指针常量,指针的指向不可修改
	//如果想让指针指向的值也不可以修改,需要声明常函数
	void ShowPerson() const {
    
    
		//const Type* const pointer;
		//this = NULL; //不能修改指针的指向 Person* const this;
		//this->mA = 100; //但是this指针指向的对象的数据是可以修改的

		//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
		this->m_B = 100;
	}

	void MyFunc() const {
    
    
		//mA = 10000;
	}

public:
	int m_A;
	mutable int m_B; //可修改 可变的
};


//const修饰对象  常对象
void test01() {
    
    

	const Person person; //常量对象  
	cout << person.m_A << endl;
	//person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
	person.m_B = 100; //但是常对象可以修改mutable修饰成员变量

	//常对象访问成员函数
	person.MyFunc(); //常对象不能调用const的函数

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

**4.4 友達**

友達はただの宣言であり、このクラスのメンバーになることは絶対に不可能です

フレンドの目的は、関数またはクラスをこのクラスのフレンドとして宣言し、
このクラスのプライベート メンバーにアクセスできるようにすることです。

フレンドの 3 つの実装 フレンド
としてのグローバル機能
フレンドとしてのクラス フレンド
としてのメンバー機能

friend void goodGay(Building * building);
friend class goodGay;
friend void goodGay::visit();

4.5 演算子のオーバーロード

演算子のオーバーロードの概念: 既存の演算子を再定義し、異なるデータ型に適応する別の関数を追加します。

4.6 継承

C++ のクラスには、パブリック、プロテクト、プライベートの 3 つのアクセス権 (アクセス制御とも呼ばれます) があります。

ここに画像の説明を挿入
ここに画像の説明を挿入

概念 1: 静的
C++ のクラスのメンバーのアクセス レベルは、パブリック、プロテクト、プライベートに分類できます。パブリックはアクセスレベルが最も低く、誰でもアクセスできます。
クラスのパブリック メンバー変数およびメンバー関数には、クラスのメンバー関数およびインスタンス変数を通じてアクセスできます。保護された
アクセス レベルは中です。クラスの保護されたメンバー変数およびメンバー関数には、クラスのインスタンス変数を通じてアクセスできません。クラス。ただし、クラスのフレンド機能とフレンドクラスを通じてアクセスできます。
プライベート アクセス レベルは最も高く、クラスのインスタンス変数を介してクラスのプライベート メンバー変数およびメンバー関数にアクセスすることはできません。ただし、クラスのフレンド機能とフレンドクラスを通じてアクセスできます。
これまでのところ、保護されたものとプライベートなものの間に大きな違いはないように見えますが、主な違いは 2 番目の概念にあります。
コンセプト2:
ダイナミック ダイナミック、つまりアクションの意味について。親子継承関係が含まれます。つまり、自己クラスが親クラスを継承する方法 (パブリック継承、保護された継承、プライベート継承のいずれであるか) です。
(1) パブリック継承
派生クラスはパブリックで継承され、基底クラスの各種権限はそのまま残ります。
派生クラスのメンバー関数は、基本クラスのパブリック メンバーと保護されたメンバーにアクセスできますが、基本クラスのプライベート メンバーにはアクセスできません。
派生クラスのインスタンス変数は、基本クラスのパブリック メンバーにアクセスできますが、基本クラスのメンバーが派生クラスに追加されたかのように、保護されたメンバーとプライベート メンバーにはアクセスできません。
パブリック継承は、基本クラスのパブリック メンバーと保護されたメンバーを派生クラスに含める派生クラスとみなすことができますが、プライベート メンバーは含めません。
(2) 保護された継承
派生クラスは protected を通じて継承され、派生クラス内の基本クラスのパブリック メンバーのアクセス許可が保護されます。protected と private は変更されません。
派生クラスのメンバー関数は、基本クラスのパブリック メンバーと保護されたメンバーにアクセスできますが、基本クラスのプライベート メンバーにはアクセスできません。
基本クラスのパブリック メンバーは派生クラスで保護されるため、派生クラスのインスタンス変数は基本クラスのメンバーにアクセスできません。
保護された継承は、基本クラスのパブリック メンバーと保護されたメンバーを派生クラスに組み込んだ派生クラスとみなすことができます。これらはすべて、派生クラスの保護されたメンバーですが、プライベート メンバーは含まれません。
プライベート メンバーは基本クラス内のプライバシーであり、友人を除き、すべての職員はスパイすることを許可されません。派生クラスのフレンドにはアクセスできません
(3) プライベート
継承 派生クラスはプライベートで継承され、派生クラス内の基本クラスのすべてのメンバーの権限がプライベートになります。
派生クラスのメンバー関数は、基本クラスのパブリック メンバーと保護されたメンバーにアクセスできますが、基本クラスのプライベート メンバーにはアクセスできません。
派生クラスでは基本クラスのすべてのメンバーがプライベートになるため、派生クラスのインスタンス変数は基本クラスのメンバーにアクセスできません。
プライベート継承は、基本クラスのパブリック メンバーとプロテクト メンバーを派生クラスに組み込んだ派生クラスとみなすことができます。これらはすべて派生クラスのプライベート メンバーですが、プライベート メンバーは含まれません。
プライベート メンバーは基本クラス内のプライバシーであり、友人を除き、すべての職員はスパイすることを許可されません。派生クラスのフレンドにはアクセスできません

継承の利点: == により重複コードを削減できる

class A : public B; 

クラス A は子クラスまたは派生クラスと呼ばれます クラス
B は親クラスまたは基本クラスと呼ばれます

派生クラスのメンバーには 2 つの部分が含まれます。1
つは基本クラスから継承され、もう 1 つは追加されたメンバーです。
基本クラスから継承されたメンバーは共通性を示し、新しく追加されたメンバーはそれぞれの個性を反映します。

建設と破壊の命令

https://blog.csdn.net/weixin_39731083/article/details/81903997
2. コンストラクタの呼び出し順序
基底クラスのコンストラクタ、オブジェクトメンバのコンストラクタ、派生クラス自身のコンストラクタ
3. デストラクタの呼び出し順序 派生
クラス 自デストラクタ、オブジェクトメンバのデストラクタ、基本クラスのデストラクター (構築の逆順)

4.6.5 同名メンバーの継承

オーバーロード (overload) オーバーライド (override) (仮想関数、書き換え???) 3. オーバーライト (overwrite)

https://www.cnblogs.com/kuliuheng/p/4107012.html
1.
Overload (オーバーロード) の概念が最もよく理解されている同じクラス宣言スコープ (同じスコープ内) で、まったく同じ内容を持つ複数の 2 つの関数名前は異なりますが、パラメーター (型または数値) が異なるものは、オーバーロードと呼ばれます。オーバーロードの特徴は、
(1) 同じスコープ(同じクラス内)、
(2) 関数名が同じ、
(3) パラメータが異なる、
(4) virtual キーワードがオプションであることです。

2. Override ((virtual function, rewrite???)
Override の概念は、実際には C++ ポリモーフィズムを実現するために使用されます。つまり、virtual 関数は、
親クラスで virtual として宣言された関数をサブクラスで書き換えます。プログラムの実行時に,オブジェクトの種類に応じて、同名の関数を親クラス内で呼び出すか、クラス内で呼び出すかを判断します。
典型的な例として、親クラスでは、一般にデストラクタを仮想関数として宣言する必要があります。プログラム内では、親クラス型のポインタがサブクラス オブジェクトを指すように使用されるため、メモリ リークを回避するには、親クラスのデストラクタを仮想関数として宣言する必要があります。

Override の特徴は、
(1) スコープが異なる (派生クラスと基底クラスにそれぞれ存在する)、
(2) 関数名が同じ、
(3) パラメータのリストがまったく同じ、
(4)です。基本クラス関数には仮想キー Character が必要です。

3. 上書き(書き換え)
親クラスの関数が仮想関数として宣言されておらず、サブクラスで同名の関数が書き換えられる

書き換えは、派生クラスの関数が同じ名前の基本クラス関数をシールドする (または「隠す」)ことを意味します。この C++ の隠れたルールが問題の複雑さを突然増大させます。議論のために 2 つの状況に分けて説明します。

(1) 派生クラスの関数が基底クラスの関数と同じ名前で、パラメータが異なる場合。そしてこのとき、virtualキーワードの有無に関わらず、基底クラスの機能は隠蔽されます(オーバーロードと混同しないように注意してください)。
(2)派生クラスの関数が基底クラスの関数と同じ名前および同じパラメータを持つが、基底クラスの関数に virtual キーワードがない場合。このとき、基底クラスの関数は非表示になります(カバレッジと混同しないように注意してください)。

class Base{
    
    
public:
    virtual int fcn();
};
class Derived1:public Base{
    
    
public:
    //隐藏基类的fcn,这个fcn不是虚函数
    //Derived1继承了Base::fcn()的定义
    int fcn(int);         //形参类别与Base中的fcn不一样
    virtual void f2();    //是一个新的虚函数,在Base中不存在
};
class Derived2:public D1{
    
    
publicint fcn(int);        //是一个非虚函数,隐藏了Derived1::fcn(int)
    int fcn();           //覆盖了Base的虚函数fcn
    void f2();           //覆盖了Derived1的虚函数f2

4.6.6 同名の静的メンバーの継承

質問: 継承内で同じ名前を持つ静的メンバーにサブクラス オブジェクトでアクセスするにはどうすればよいですか?
同じ名前の静的メンバーと非静的メンバーは同じ方法で処理されます。

  • 同じ名前のサブクラス メンバーに直接アクセスできる
  • 親クラスと同じ名前のメンバーにアクセスするには、親クラスのスコープを追加する必要があります
//同名成员属性
void test01()
{
    
    
	//通过对象访问
	cout << "通过对象访问: " << endl;
	Son s;
	cout << "Son  下 m_A = " << s.m_A << endl;
	cout << "Base 下 m_A = " << s.Base::m_A << endl;

	//通过类名访问
	cout << "通过类名访问: " << endl;
	cout << "Son  下 m_A = " << Son::m_A << endl;
	cout << "Base 下 m_A = " << Son::Base::m_A << endl;
}

4.6.7 多重継承構文

C++ では、クラスが複数のクラスを継承でき
ます文法: class 子类 :继承方式 父类1 , 继承方式 父类2...
多重継承により、親クラスに同じ名前のメンバーが現れる可能性があり、それを区別するためにスコープを追加する必要があります。実際の
C++ の開発では、複数のクラスを使用することは推奨されません。継承

//语法:class 子类:继承方式 父类1 ,继承方式 父类2 
class Son : public Base2, public Base1 
{
    
    
public:
	Son()
	{
    
    
		m_C = 300;
		m_D = 400;
	}
public:
	int m_C;
	int m_D;
};

4.6.8 ダイヤモンドの継承

注: 仮想基本クラス

//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep : virtual public Animal {
    
    };
class Tuo   : virtual public Animal {
    
    };
class SheepTuo : public Sheep, public Tuo {
    
    };

要約:

  • ダイヤモンド継承によって引き起こされる主な問題は、サブクラスが同じデータの 2 つのコピーを継承し、リソースの無駄と無意味が生じることです。
  • 仮想継承を使用すると、ダイヤモンド継承の問題を解決でき、仮想基本クラス内にデータのコピーが 1 つだけ存在することが保証されます。

4.7 ポリモーフィズム

ポリモーフィズムは、C++** の 3 つの主要なオブジェクト指向機能の 1 つです。
ポリモーフィズムは、2 種類の
静的ポリモーフィズムに分類されます。関数のオーバーロードと演算子オーバーロードは静的ポリモーフィズム、関数名 (オーバーロード) を再利用します。 動的
ポリモーフィズム: 派生クラスと仮想関数 ランタイムの実現ポリモーフィズム (override キーワードは仮想仮想関数で使用されます)

override是C++11中的一个新的继承控制关键字。override确保在派生类中声明的重载函数跟基类的 virtual虚函数有相同的声明。

override明确地表示一个函数是对基类中一个虚函数的重载。更重要的是,它会检查基类虚函数和派生类中重载函数的签名不匹配问题。如果签名不匹配,编译器会发出错误信息。

override表示函数应当重写基类中的虚函数(用于派生类的虚函数中)

静的ポリモーフィズムと動的ポリモーフィズムの違い:

  • 静的多態性関数アドレスの早期バインディング - コンパイル中に関数アドレスを決定します
  • 動的多態性関数アドレス遅延バインディング - ランタイムが関数アドレスを決定します
//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编
总结
//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象

4.7.3 純粋仮想関数と抽象クラス (または純粋仮想クラスと呼ばれる)

違い: 抽象クラス (純粋仮想関数) と仮想基本クラス (仮想継承)

ポリモーフィズムでは、親クラスでの仮想関数の実装は通常は無意味であり、主にサブクラスによって書き換えられた内容を呼び出すため、仮想関数を純粋仮想関数
に変更できます。純粋仮想関数の構文:クラスに純粋な関数がある場合仮想関数、このクラスはとも呼ばれます
virtual 返回值类型 函数名 (参数列表)= 0 ;
抽象クラス
抽象クラスの機能:

  • オブジェクトをインスタンス化できませんでした
  • サブクラスは抽象クラスの純粋仮想関数をオーバーライドする必要があります。そうでない場合は、サブクラスも抽象クラスに属します。
class Base
{
    
    
public:
	//纯虚函数
	//类中只要有一个纯虚函数就称为抽象类
	//抽象类无法实例化对象
	//子类必须重写父类中的纯虚函数,否则也属于抽象类
	virtual void func() = 0;
};

4.7.5 仮想および純粋仮想破壊

親クラスのポインタがサブクラスのオブジェクトを指していることが原因で発生する問題

ポリモーフィズムを使用する場合、サブクラスにヒープ領域に割り当てられた属性がある場合、親クラスのポインタは解放時に親クラスのデストラクタコードを呼び出してしまい、サブクラスのデストラクタコードを呼び出すことができません
。デストラクタ定義は仮想デストラクタまたは純粋仮想デストラクタに変更されます。仮想デストラクタ
構文:
virtual ~类名(){}
純粋仮想デストラクタ構文:
virtual ~类名() = 0;
`クラス名::~クラス名(){}

1. 仮想デストラクタまたは純粋仮想デストラクタは、親クラス ポインタを介してサブクラス オブジェクトを解放する問題を解決するために使用されます
2. サブクラスにヒープ データがない場合、仮想デストラクタまたは純粋仮想デストラクタとして記述することはできません
3 . 純粋な仮想デストラクタを持つクラスも抽象クラスを所有

class Animal {
    
    
public:
	Animal()
	{
    
    
		cout << "Animal 构造函数调用!" << endl;
	}
	virtual void Speak() = 0;
	//析构函数加上virtual关键字,变成虚析构函数
	//virtual ~Animal()
	//{
    
    
	//	cout << "Animal虚析构函数调用!" << endl;
	//}
	virtual ~Animal() = 0;
};

Animal::~Animal()
{
    
    
	cout << "Animal 纯虚析构函数调用!" << endl;
}

//和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。

class Cat : public Animal {
    
    
public:
	Cat(string name)
	{
    
    
		cout << "Cat构造函数调用!" << endl;
		m_Name = new string(name);
	}
	virtual void Speak()
	{
    
    
		cout << *m_Name <<  "小猫在说话!" << endl;
	}
	~Cat()
	{
    
    
		cout << "Cat析构函数调用!" << endl;
		if (this->m_Name != NULL) {
    
    
			delete m_Name;
			m_Name = NULL;
		}
	}

public:
	string *m_Name;
};

void test01()
{
    
    
	Animal *animal = new Cat("Tom");
	animal->Speak();

	//通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
	//怎么解决?给基类增加一个虚析构函数
	//虚析构函数就是用来解决通过父类指针释放子类对象
	delete animal;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

5 ファイル操作ストリームオブジェクト

オブジェクト指向の考え方です。
プログラムの実行中に生成されるデータはすべて一時的なデータであり、プログラムの実行が終了すると解放されます。データはファイルを通じて永続化できます。C ++ では、ファイル操作にヘッダーを含める必要があります。ファイル< fストリーム >

次の 2 つのファイル タイプがあります。

  1. テキスト ファイル- ファイルはASCII形式のテキストとしてコンピュータに保存されます。
  2. バイナリ ファイル- ファイルはバイナリ形式のテキストでコンピュータに保存され、通常はユーザーが直接読み取ることはできません。

3 種類のファイル操作:
3. ofstream: 書き込み操作
4. ifstream: 読み取り操作
5. fstream: 読み取りおよび書き込み操作

おすすめ

転載: blog.csdn.net/qq_46084757/article/details/127040345