目次
1. C++では、構造体に変数を定義できるだけでなく、関数も定義できます。
6. address および const アドレス演算子のオーバーロード
導入
C++ はオブジェクト指向です。
C と C++ の違い
C はプロセス指向言語であり、C++ は C 言語のスーパーセットであり、カプセル化、継承、ポリモーフィズムといったオブジェクト指向の機能が追加されています。カプセル化によりコードの実装の詳細を隠すことができるため、コードがモジュール化され、管理や拡張が容易になります。継承により、サブクラスは親クラスのコードとプロパティを再利用できるようになります。ポリモーフィズムとは、親クラスの仮想関数をサブクラスで書き換えることで同じインターフェースを実装し、異なる動作を実現することです。
C と C++ ではメモリの管理方法が異なります。C++ では主に new と delete が使用されます。さらに、C++ では関数のオーバーロードや参照などの概念も追加されています。
C++ と Java の関係と違い
C++ と Java はどちらもオブジェクト指向言語です。C++ を実行するには、実行可能ファイルにコンパイルする必要があります。Java はコンパイルされ、jvm 仮想マシン上で実行されます。そのため、Java は優れたクロスプラットフォーム機能を備えていますが、実行効率はそれほど高くありません。 C++ と同様に優れています。
C++ のメモリはプログラマが手動で管理する必要がありますが、Java はマーク リサイクル アルゴリズムを使用して仮想マシンで完成させることができます。
C++ にはポインターがありますが、Java にはなく、Java には参照のみがあります。
Java と C++ には両方ともコンストラクターがあり、C++ にはデストラクターがありますが、Java にはありません。
C++ と Python の違い
Python は解釈と実行のためのスクリプト言語であり、C++ はコンパイル済み言語であるため、Python のクロスプラットフォームは C++ よりも優れています。
Python はさまざまなコード ブロックを区別するためにインデントを使用し、C++ は中括弧を使用します。
C++ では最初に変数の型を定義する必要がありますが、Python では定義しません。
Python のライブラリは C++ よりも多く、使いやすいです。
1. クラスとの最初の知り合い
1. C++では、構造体に変数を定義できるだけでなく、関数も定義できます。
struct Student
{
void SetStudentInfo(const char* name, const char* gender, int age)
{
strcpy(_name, name);
strcpy(_gender, gender);
_age = age;
}
void PrintStudentInfo()
{
cout<<_name<<" "<<_gender<<" "<<_age<<endl;
}
char _name[20];
char _gender[3];
int _age;
};
移行:
int main()
{
Student s;
s.SetStudentInfo("哈哈", "女", 18);
return 0;
}
2. クラス定義
class className
{
// 类体:由成员函数和成员变量组成
}; //分号
クラス内の要素はクラスのメンバーと呼ばれ、クラス内のデータはクラスの属性またはメンバー変数と呼ばれ、クラス内の関数はクラスのメソッドまたはメンバー関数と呼ばれます。
クラスを定義するには 2 つの方法があります。
1. 宣言と定義はすべてクラス本体に配置されますが、クラス内にメンバ関数が定義されている場合、コンパイラはそれをインライン関数として扱う可能性があることに注意してください。
2. 宣言は .h ファイルに配置され、クラス定義は .cpp ファイルに配置されます(2 番目の方法の方が優れています)。
//person.h
class Person
{
public:
void show()
{
cout << _name << " " << _age << endl;
}
public:
char* _name;
int _age;
};
//person.cpp
#include "person.h"
void Person::show()
{
cout << _name << " " << _age << endl;
}
3. クラスアクセス修飾子とカプセル化
3.1 アクセス修飾子
C++ でカプセル化を実現する方法: クラスを使用してオブジェクトのプロパティとメソッドを組み合わせてオブジェクトをより完璧にし、アクセス権を通じてそのインターフェイスを外部ユーザーに選択的に提供します。
アクセス修飾子:
保護された、プライベート、パブリック
【アクセス修飾子の説明】
1. publicで変更したメンバはクラス外から直接アクセス可能
2. protected および private の変更されたメンバーにはクラスの外部から直接アクセスできません (ここでは protected と private は似ています)
3. アクセス権の範囲は、アクセス修飾子の出現から始まり、次にアクセス修飾子が出現するまでとなります。
4. デフォルトのアクセス権限はクラスはプライベート、構造体はパブリック(構造体はCと互換性があるため)アクセス修飾子はコンパイル時にのみ役立ちます。データがメモリにマップされるときは、アクセス修飾子に違いはありません。
C++ の構造体とクラスの違いは何ですか?
回答: C++ は C 言語と互換性がある必要があるため、C++ の struct を構造体として使用できます。さらに、C++ の struct を使用してクラスを定義することもできます。
class がクラスを定義するのと同じですが、struct のメンバーのデフォルトのアクセス モードが public で、class のメンバーのデフォルトのアクセス モードが private である点が異なります。
3.2 梱包
オブジェクト指向の 3 つの主要な特徴: カプセル化、継承、ポリモーフィズム。
カプセル化: オブジェクトのプロパティと実装の詳細を非表示にし、オブジェクトと対話するインターフェイスのみを公開します。
4. クラスの範囲
クラスは新しいスコープを定義し、クラスのすべてのメンバーはクラスのスコープ内にあります。クラス外のメンバーを定義するには、::スコープ パーサーを使用して、メンバーがどのクラス ドメインに属しているかを示す必要があります。
class Person
{
public:
void show()
{
cout << _name << " " << _age << endl;
}
public:
char* _name;
int _age;
};
void Person::show()
{
cout << _name << " " << _age << endl;
}
5. クラスのインスタンス化
クラス型を使用してオブジェクトを作成するプロセスは、クラスのインスタンス化と呼ばれます。
1. クラスを格納するための実際のメモリ領域を割り当てずにクラスを定義する
2. クラスは複数のオブジェクトをインスタンス化でき、インスタンス化されたオブジェクトは実際の物理空間を占有し、クラス メンバー変数を格納します。
たとえば、多くのフィギュアはペーパーマンをベースに作成できますが、メーカーの問題により各フィギュアに差異が生じる可能性があります。
6. クラスオブジェクトモデル
6.1 クラスオブジェクトのサイズを計算する方法
オブジェクトに格納されているメンバー変数はありますが、メンバー関数はありません。各オブジェクトには独立したメンバー変数があります
クラスまたはクラス オブジェクトのサイズを計算します。メンバー変数のみを確認し、メモリ アライメント ルールは構造と一致します。
空のクラス: 1 バイト。異なる空のクラスを区別するために、空のクラスはオブジェクトをインスタンス化することもでき、各オブジェクトのアドレスは異なるため、コンパイラは暗黙的に空のクラスにバイトを追加します。
6.2 クラスオブジェクトの格納方法
メンバー変数のみが保存され、メンバー関数はパブリック コード セグメントに格納されます。
class A1 {
public:
void f1() {}
private:
int _a;
};
// 类中仅有成员函数
class A2 {
public:
void f2() {}
};
// 类中什么都没有---空类
class A3
{};
//sizeof(A1) : __4____ sizeof(A2) : __1____ sizeof(A3) : ___1___
クラスのサイズは実際にはクラス内の「メンバ変数」の合計です。もちろんメモリアライメントも必要です。空クラスのサイズに注意してください。空クラスは特別です。コンパイラは空クラスを与えます。クラスを一意に識別するバイト
6.3 構造体メモリのアライメント規則
+ 構造体の最初のメンバーのオフセットは 0
+ 他のメンバー変数は、アライメント番号の整数倍のアドレスに従って格納される必要があります
+ アライメント番号 = min (コンパイラのデフォルトのアライメント番号、このアライメント番号member)、Linux では 4 です。vs では、8
+ 構造体の合計サイズは最大アライメント数の整数倍です
+ 構造がネストされている場合、ネストされた構造はそれ自体の最大アライメントの整数倍にアライメントされ、構造全体のサイズはすべての最大アライメント (ネストされた構造のアライメントを含む) の整数倍になります。
7. このポインタ
7.1 このポインタは何ですか
非静的クラスのメンバー関数オブジェクトのみがこのポインターを持ち、このポインターはクラスのメンバー関数でのみ使用でき、メンバー関数が呼び出されるオブジェクトを指します。
このポインターを非表示にする: メンバー関数を呼び出すとき、実際のパラメーターを this に渡すことはできません。メンバー関数を定義する場合、これに対する仮パラメーターを明示的に宣言することはできません。メンバー関数内に書き出すことができます。
class Date
{
public:
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
//cout<< this->_year << this->_month << this->_day <<endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
//this->_year = year;
_month = month;
_day = day;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1, d2;
d1.SetDate(2018, 5, 1);
d2.SetDate(2018, 7, 1);
d1.Display();
d2.Display();
//void Display(Date * this) 形参
//{}
return 0;
}
C++ コンパイラーは、各「非静的メンバー関数」に隠しポインター パラメーターを追加します。これにより、ポインターは現在のオブジェクト (関数の実行時に関数を呼び出すオブジェクト) を指し、その関数内のすべてのメンバー変数の演算が行われます。関数本体は すべての操作がユーザーに対して透過的であるというだけです。つまり、ユーザーが操作を渡す必要がなく、コンパイラーが自動的に操作を完了します。
7.2 このポインタの特徴
1. このポインタの型: class type * const
2. 「メンバー関数」内でのみ使用できます。 3. このポインタは、実際には
、本質的に、オブジェクトがメンバー関数を呼び出すときのメンバー関数の仮パラメータです。オブジェクトのアドレスは、this パラメータに渡される実際のパラメータとして使用されます。したがって、 this ポインタはオブジェクトに格納されません。4. this ポインタは、メンバー関数の最初の暗黙的なポインタ パラメータです。通常、これはコンパイラによって ecx レジスタを通じて自動的に渡され、ユーザーが渡す必要はありません。仮パラメータであるため、通常はスタックに格納されます。
このポインタは null であってもよいでしょうか?
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
void Show()
{
cout << "Show()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;//空指针不是语法错误,编译不会报错
p->PrintA();//运行到这里时,崩溃,因为此时 调用 _a,this->_a
//把p这个空指针作为实参赋给this,对空指针解引用。
p->Show();
}
メンバー関数がオブジェクトに存在しないため、p は NULL ポインターを使用せずにメンバー関数ページを呼び出します。
次に、クラスのメンバー関数
クラスの 6 つのデフォルトのメンバー関数:
初期化とクリーンアップ: コンストラクター、デストラクター
コピー代入: コピー構築、代入演算子のオーバーロード
アドレス取得オーバーロード: 通常のオブジェクトと const オブジェクトのアドレスを取得します。
1. コンストラクター
コンストラクターは、クラス名と同じ名前を持つ特別なメンバー関数であり、クラス型オブジェクトの作成時にコンパイラーによって自動的に呼び出され、各データ メンバーが適切な初期値を持つようにし、一生に 1 回だけ呼び出されます。オブジェクトのサイクル。
主なタスクはオブジェクトを初期化することです。特徴
は以下のとおりです。1. 関数名はクラス名と同じです。
2. 戻り値はありません。
3. コンパイラは、オブジェクトがインスタンス化されるときに、対応するコンストラクターを自動的に呼び出します。
4. コンストラクターはオーバーロードできます。5. クラス内でコンストラクターが明示的に定義されていない場合、C++ コンパイラーはパラメーターなしでデフォルトのコンストラクターを自動的に生成しますが、明示的に定義されると、コンパイラーはそれを生成しなくなります。
6. パラメータなしのコンストラクタとデフォルト コンストラクタは両方ともデフォルト コンストラクタと呼ばれ、デフォルト コンストラクタは 1 つだけ存在できます。
注: 引数のないコンストラクター、完全なデフォルトのコンストラクター、およびデフォルトでコンパイラーによって生成されるコンストラクターはすべて、デフォルトのメンバー関数と見なすことができます。
7. コンパイラーによって生成されたデフォルトのコンストラクターは、カスタム型メンバーのデフォルトのメンバー関数を呼び出します。
class Date
{
public:
// 1.无参构造函数
Date()
{}
// 2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date d1; // 调用无参构造函数
Date d2(2015, 1, 1); // 调用带参的构造函数
// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
Date d3();
}
2. デストラクター
オブジェクトが破棄されると、デストラクターが自動的に呼び出されます。
2.1 特徴
デストラクターは特別なメンバー関数です。
その特徴は次のとおりです。
1. デストラクタ名は クラス名の前に~
という文字を追加します。 2. パラメータも戻り値もありません。
3. クラスにはデストラクターが 1 つだけあります。明示的に定義されていない場合、システムはデフォルトのデストラクターを自動的に生成します。
4. オブジェクトのライフサイクルが終了すると、C++ コンパイル システムは自動的にデストラクターを呼び出します。5. コンパイラーによって生成されたデフォルトのデストラクターは、カスタム型メンバーのデストラクターを呼び出します。
typedef int DataType;
class SeqList
{
public:
~SeqList()
{
if (_pData)
{
free(_pData); // 释放堆上的空间
_pData = NULL; // 将指针置为空
_capacity = 0;
_size = 0;
}
}
private:
int* _pData;
size_t _size;
size_t _capacity;
};
3. コンストラクターのコピー
3.1 コンセプト
オブジェクトと同一の新しいオブジェクトを作成します。既存のオブジェクト。すぐにインスタンス化されるオブジェクトをコピーして初期化します。
3.2 特徴
コピー コンストラクターも特殊なメンバー関数であり、その特徴は次のとおりです。
1. コピー コンストラクターはコンストラクターのオーバーロード形式です。
2. コピー コンストラクターにはパラメーターが 1 つだけあり、参照によって渡す必要があります。値によって渡す方法では無限の再帰呼び出しが発生します。
class Date
{
public:
// 1.无参构造函数
Date()
{}
// 2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//3.拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(d1);//调用拷贝构造函数
return 0;
}
3. 定義が表示されない場合、システムはデフォルトのコピー コンストラクターを生成します。デフォルトのコピー コンストラクター オブジェクトはメモリに保存され、バイト オーダーでコピーされます。この種のコピーは、シャロー コピー、または値コピーと呼ばれます。
4. 浅いコピーと深いコピーの違いについては、まさにこの違いがあるため、後で説明します。独自のコピー構築を実装する必要がある
4. 代入演算子のオーバーロード
4.1 演算子のオーバーロード
関数名は、キーワード演算子の後に、オーバーロードする必要がある演算子記号が続きます。
関数プロトタイプ:戻り値型演算子演算子(パラメータリスト)
1. オーバーロードされた演算子には、クラス型または列挙型のオペランドが必要です。
2. 組み込み型に使用される演算子の意味は変更できません。たとえば、組み込み整数 + はその意味を変更できません。 3. オーバーロードされた
関数がクラス メンバーとして使用される場合、その仮パラメータは 1 であるように見えます。オペランドの数より小さいメンバー関数 4.
演算子にはデフォルトの仮パラメータ this があり、最初の仮パラメータ
5. .*、::、sizeof、?:, に制限されています。 上記の 5 つの演算子はオーバーロードできないことに注意してください。
bool operator==(const Date& d1, const Date& d2)
{
return d1._year == d2._year;
&& d1._month == d2._month
&& d1._day == d2._day;
}
//bool operator==(Date* this, const Date& d2)
// 这里需要注意的是,左操作数是this指向的调用函数的对象
bool operator==(const Date& d2)
{
bool operator==(Date* const this, const Date & d)
{
return _year == d2._year;
&& _month == d2._month
&& _day == d2._day;
}
}
4.2 代入演算子のオーバーロード
Date& operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
}
1. パラメーターの型
2. 戻り値
3. 自分自身に値を割り当てているかどうかを確認します。
4. *this を返します。
5. クラスが代入演算子のオーバーロードを明示的に定義していない場合、コンパイラーは代入演算子のオーバーロードも生成して、その値のコピーを完了します。バイトオーダーのオブジェクト。6. 課題のコピーを自分で書かなければならない場合もあります
int main()
{
Date d1;
Date d2(2018,10, 1);
// 这里d1调用的编译器生成operator=完成拷贝,d2和d1的值也是一样的。
d1 = d2;
return 0;
}
5.constメンバ
const 変更クラスのメンバー関数
const 修飾されたクラス メンバー関数は、const メンバー関数と呼ばれます。const 修飾されたクラス メンバー関数は、メンバー関数の暗黙的な this ポインターを実際に変更し、クラスのメンバーがメンバー関数内で変更できないことを示します。
6. address および const アドレス演算子のオーバーロード
デフォルトのものを使用するだけで、他の人に指定したコンテンツを取得させたいときに自分でリロードできます。
class Date
{
public:
Date* operator&()
{
return this;
}
const Date* operator&()const
{
return this;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
3. 施工業者との綿密な連携
1. コンストラクター本体の割り当て
コンストラクター本体のステートメントは、初期化ではなく、初期値の割り当てのみを呼び出すことができます。初期化は 1 回しか行えず、コンストラクター本体は複数回割り当てることができるためです。
2. 初期化リスト
コロンの後にデータ メンバーのコンマ区切りのリストが続き、各「メンバー変数」の後に
括弧で囲まれた初期値または式が続きます。
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
各メンバー変数は、初期化リストに1 回だけ出現できます(初期化は 1 回だけ初期化できます)。
クラスには次のメンバーが含まれており、初期化のために初期化リストに配置する必要があります:
参照メンバー変数
const メンバー変数
カスタム タイプ メンバー (このクラスにはデフォルトのコンストラクターはありません)
class B
{
public:
B(int a, int ref)
:_aobj(a)
,_ref(ref)
,_n(10)
private:
A _aobj; // 没有默认构造函数
int& _ref; // 引用
const int _n; // const
};
初期化リストの初期化を使用するようにしてください。初期化リストを使用するかどうかに関係なく、カスタム型のメンバー変数の場合は、最初に初期化リストを使用して初期化する必要があります。
クラス内でメンバー変数が宣言される順序は、初期化リスト内で初期化される順序となります。
知らせ:
組み込み型が初期化子リストを使用するかどうかは関係ありません。
カスタム型は初期化子リストを使用し、独自のコンストラクターが呼び出されます。
未使用: デフォルトのコンストラクターが最初に呼び出され、次に独自のコンストラクターが呼び出され、その後割り当てられます。
3. 明示的なキーワード
コンストラクターはオブジェクトの構築と初期化ができるだけでなく、単一パラメーターのコンストラクターの型変換関数も備えています。
コンストラクターを明示的に変更すると、単一引数のコンストラクターの暗黙的な変換が禁止されます。
class Date
{
public:
Date(int year)
:_year(year)
{}
explicit Date(int year)
:_year(year)
{}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date d1(2018);
// 用一个整形变量给日期类型对象赋值
d1 = 2019;
}
4、静的メンバー
1.コンセプト
static として宣言されたクラス メンバーはクラスの static メンバーと呼ばれ、static で変更されたメンバー変数は static メンバー変数と呼ばれ、static で変更されたメンバー関数は static メンバー関数と呼ばれます。静的メンバー変数はクラスの外で初期化する必要があります
class A
{
public:
A() { ++_scount; }
A(const A& t) { ++_scount; }
static int GetACount() { return _scount; }
private:
static int _scount;
};
int A::_scount = 0;//初始化
void TestA()
{
cout << A::GetACount() << endl;
A a1, a2;
A a3(a1);
cout << A::GetACount() << endl;
}
2. 特徴
1. 静的メンバーはすべてのクラス オブジェクトで共有され、特定のインスタンスに属しません。
2. 静的メンバー変数は、static キーワードを追加せずにクラスの外部で定義する必要があります。 3. クラスの静的メンバーは、クラス名::静的メンバーまたはオブジェクト
を使用できます。 .アクセスする静的メンバー4. 静的メンバー関数には隠蔽された this ポインターがなく、非静的メンバーにはアクセスできません5. クラスの通常のメンバーと同様、静的メンバーにも 3 つのアクセス レベルがあります: public、protected、private、戻り値を持つこともできます
5、C++11 メンバーの初期化
private:
// 非静的メンバー変数には、メンバーの宣言時にデフォルト値を与えることができます。
int a = 10;
6、運命?ユユアン!
フレンドはフレンド関数とフレンドクラスに分けられます
が、フレンドは結合度を高め、カプセル化を破壊するため、フレンドを頻繁に使用するべきではありません。
1.フレンド機能
フレンド関数は、クラスのプライベートおよび保護されたメンバーにアクセスできますが、クラスのメンバー関数にはアクセスできません。
フレンド関数は const で変更できません
フレンド関数は、クラスアクセス修飾子による制限を受けず、クラス定義内のどこでも宣言できます。
関数は複数のクラスのフレンド関数になることができます
フレンド関数の呼び出しは通常の関数と同じです
2 フレンドクラス
フレンド クラスのすべてのメンバー関数は、別のクラスのフレンド関数になることができ、別のクラスの非パブリック メンバーにアクセスできます。
友情関係は一方通行であり、交換することはできません。
友情は渡せない
class Date;
class Time
{
friend class Date; // 声明日期类为时间类的友元类,则在Date类中就直接访问Time类中的私有成
员变量
};
セブン、インナークラス
コンセプトと特長
コンセプト:
クラスが別のクラスの内部で定義されている場合、その内部クラスは内部クラスと呼ばれます。この内部クラスは現時点では独立したクラスであり、外部クラスに属しておらず、ましてや外部クラスのオブジェクトを通じて内部クラスを呼び出すことはできません。外部クラスには、内部クラスへの特権アクセスがありません
。 注: 内部クラスは、外部クラスのフレンド クラスです。フレンド クラスの定義に注意してください。内部クラスは、外部クラスのオブジェクト パラメーターを通じて、外部クラスのすべてのメンバーにアクセスできます。しかし、外側の階級は内側の階級の友人ではありません。
特性:
1. 内部クラスは、外部クラスで public、protected、または private として定義できます。
2. 内部クラスは、外部クラスのオブジェクト/クラス名を使用せずに、外部クラスの静的メンバーと列挙型メンバーに直接アクセスできることに注意してください。
3. sizeof (外部クラス) = 外部クラス、内部クラスとは関係ありません