C++ のクラスとオブジェクト (詳細なレビュー)

クラスはオブジェクトを実現したものです。オブジェクト内のクラスは抽象概念であり、クラスはプログラムの最初に定義されるオブジェクトです。クラスによって定義されるオブジェクトは、現実世界の実際のオブジェクトである場合もあれば、実生活から抽象化されたオブジェクト。

 1.1 C++ クラス

1.1.1 クラスの概要

オブジェクト指向ではオブジェクトをクラスを定義して宣言する必要がありますが、オブジェクトとは一種のイメージであり、コードを記述する際にはクラスを定義することでオブジェクトの機能を実現します。

C++ のクラスは、中国語のクラス、分類、型とは異なり、統一されたものの概要、または特定の階層構造の異なるノードとなる特別な概念です。たとえば、すべてのコンピューターをコンピューター クラスとしてパッケージ化したり、すべての動物を動物クラスとして記述したりすることができます。現実の多くのものには多くの類似点があり、これらの類似したものをクラスとして記述することで作業負荷を軽減できます。

クラスは新しいデータ型であり、構造体に似ています。構造体はさまざまなデータ型のコレクションであり、クラスには構造体、つまり関数に基づいてデータ型を操作できる追加の動作があります。

1.1.2 クラスの宣言と定義

1.1.1 節でクラスの概念について少し説明しますが、クラスはユーザが独自に開発した型であることがわかります。プログラム内でクラスの型を使用したい場合は、必要に応じて独自のクラスを設計して宣言するか、他の人が設計したクラスを使用する必要があります。クラスを設計する方法という本題に移りましょう。

クラス宣言の形式は次のとおりです。

class クラス名識別子

{

        公共:

                データメンバーの宣言。

                メンバー関数の宣言。

        プライベート:

                データメンバーの宣言。

                メンバー関数の宣言。

        保護中:

                データメンバーの宣言。

                メンバー関数の宣言。

};

クラス宣言形式の説明は次のとおりです。

  class はクラス構造を定義するキーワードで、中括弧内はクラス本体またはクラス空間と呼ばれます。

  クラス名識別子はクラス名を指定します。クラス名はオブジェクトを宣言できる新しいデータ型です。

  クラス メンバーには、関数とデータの 2 つのタイプがあります。

  中括弧内はクラス メンバーを定義および宣言する場所で、キーワード public、private、および protected はクラス メンバー アクセスの修飾子です。 

クラス内のデータ メンバーの型は、整数、浮動小数点、文字、配列、ポインターおよび参照 (&) などを含む任意の型にすることができ、オブジェクトにすることもできます。別のクラスのオブジェクトはこのクラスのメンバーとして使用できますが、独自のクラスのオブジェクトは独自のクラスのメンバーとして使用できません。また、独自のクラスのポインターと医療オブジェクトは独自のクラスのメンバーとして使用できます。

注: クラス構造を定義し、構造を定義するときは、中括弧の後にセミコロンが必要です。

次のように、チーム情報クラスを宣言します。

class Cbasket
{
    /*数据成员*/
    int num;
    char name[128];
    char clothes[28];
    /*成员函数*/
    int setnum(int m_num);
    int getnum();
    int setname(char m_name[128]);
    char* getname();
    int setclothes(char m_clothes[28]);
    char* getclothes();
};

コードでは、class キーワードを使用してクラスの構造を定義します。Cbasket は、定義されたチーム情報のクラス名です。中括弧内には、プレーヤーの番号、名前、衣服のサイズを表す 3 つのデータ メンバーが含まれています (Cbasket 属性) ) には、Cbasket クラスの動作を表す 6 つのメンバー関数が含まれています。

 1.1.3 クラスの実装

セクション 1.1.2 では、Cbasket クラス内のクラスのメンバーを宣言するだけです。ただし、このクラスのメソッド、つまりメンバー関数を使用するには、そのクラス固有の操作を定義する必要があります。クラス内でメソッドを定義する方法を見てみましょう。

1 つ目の方法: クラス本体でクラスのメンバー関数を定義します。次のコードは Basket.h ヘッダー ファイルに格納され、クラスのメンバー関数はクラス本体で定義されます。

#include<iostream>
#include<string.h>
using namespace std;

class Cbasket
{
public:
    //数据成员
    int m_num;
    char m_name[128];
    char m_clothes[28];
    //成员函数
    int setnum(int num)
    {
        m_num=num;
        return 0;     //执行成功返回0
    }
    int getnum()
    {
        return m_num;
    }
    int setname(char name[128])
    {
        strcpy(m_name,name);
        return 0;    //执行成功返回0
    }
    char* getname()
    {
        return m_name;
    }
    int setclothes(char clothes[28])
    {
        strcpy(m_clothes,clothes);
        return 0;    //执行成功返回0
    }
    char* getclothes()
    {
        return m_clothes;
    }
};

2 番目の方法: メンバー関数の実装をクラス本体の外側のクラス本体に配置します。ただし、クラス メンバーがクラス本体の外側で定義されている場合は、ドメイン演算子 "::" を使用してクラス内に配置する必要があります。本体とクラス本体間 外部効果は同じですが、具体的な配置位置が異なります。具体的な違いについては、以下のコードと前のブロックのコードの違いを確認してください。

#include<iostream>
#include<string.h>
using namespace std;

class Cbasket
{
public:
    //数据成员
    int m_num;
    char m_name[128];
    char m_clothes[28];
    //成员函数
    int setnum(int num);
    int getnum();
    int setname(char name[128]);
    char* getname();
    int setclothes(char clothes[28]);
    char* getclothes();
};
//类成员函数的实现部分
    int basket::setnum(int num)
    {
        m_num=num;
        return 0;     //执行成功返回0
    }
    int basket::getnum()
    {
        return m_num;
    }
    int basket::setname(char name[128])
    {
        strcpy(m_name,name);
        return 0;    //执行成功返回0
    }
    char* basket::getname()
    {
        return m_name;
    }
    int basket::setclothes(char clothes[28])
    {
        strcpy(m_clothes,clothes);
        return 0;    //执行成功返回0
    }
    char* basket::getclothes()
    {
        return m_clothes;
    }

クラス本体の外でメンバー関数を実装する場合は、クラス本体で関数を宣言する必要があります。そうしないと使用できなくなります。また、メンバー関数を外部で実装する場合は :: 記号を使用する必要があることに注意してください。

クラスの実装については、次の 2 つの注意事項があります。

(1) クラスのデータメンバを初期化し、メンバ関数に実装コードを追加する必要があります。クラスのデータ メンバーをクラス宣言内で初期化することはできません。次のように初期化するとエラーになります。

クラスCの人

{

        int num=10; //誤った書き込みはクラス内で初期化できません

        char name[128]="Xiaoyuan"; //誤った記述はクラス内で初期化できません

        ...................................................

        ...................................................

};       

(2) 空クラスは C++ における最も単純なクラスであり、その宣言方法は次のとおりです。

クラス Cperson{ }; 

空のクラスはプレースホルダーとしてのみ使用され、クラスのメンバーと実装は必要に応じて定義されます。

 1.1.4 オブジェクト宣言

新しいクラスを定義した後、クラス名を使用してオブジェクトを宣言できます。宣言の形式は次のとおりです。

クラス名オブジェクト名のリスト

クラス名は定義された新しいクラスの識別子であり、オブジェクト名テーブルは 1 つ以上のオブジェクトの名前です。複数のオブジェクトを宣言する場合は、カンマで区切る必要があります。

たとえば、次のようにオブジェクトを宣言します。

C 人 p; 

      複数のオブジェクトを次のように宣言します。

C 人 p1、p2、p3;

        オブジェクトを宣言した後、オブジェクトの参照について説明する必要がありますが、オブジェクトを参照するにはメンバ参照方式とオブジェクトポインタ方式の2通りがあります。

(1) 会員の参照方法

メンバー変数の参照は次のように表されます。

オブジェクト名.メンバー名 

ここで「.」はオブジェクトのメンバーを表す演算子です。

メンバー関数適用の表現は次のとおりです。

ObjectName.MemberName (パラメータリスト) 

例えば:

 C者p;

午後_インデックス;

(2) オブジェクトポインタ方式

オブジェクト宣言形式のオブジェクト名リストには、カンマ演算子で区切られた複数のオブジェクト名に加えて、オブジェクト名配列、オブジェクト名ポインタ、参照形式のオブジェクト名も使用できます。

具体的な実装は以下の通りです。

Cperson *p;

C 人物 p[10]; 

ただし、オブジェクトのメンバーを使用する場合は、「->」演算子を使用する必要があります。これはメンバーを表す演算子であり、「.」演算子と同じ意味を持ちます。「->」は、オブジェクト ポインターが指すメンバーを示すために使用されます。オブジェクト ポインターはオブジェクトへのポインターです。次に例を示します。

Cperson *p;

p->m_index;

以下は、オブジェクト データ メンバーの 2 つの表現です。

オブジェクトポインタ名 -> データメンバ

(*オブジェクトポインタ名).dataメンバー

関数の適用についても同様です。

これら 2 つの表現形式は同等です 

オブジェクト参照メンバーの使用

インスタンスでは、定義されたクラスを使用してオブジェクトを定義し、そのオブジェクトを使用してそのメンバーを参照します。

#include<iostream> 
#include<string.h>
using namespace std;
class stu{
	public:
		int m_num;
		char m_name[25];
		int m_year;
		//函数成员
		int getnum();
		int setnum(int num);
		int getyear();
		int setyear(int year);
		int setname(char name[25]);
		char* getname();
};


int stu::getnum()
{
	return m_num;
}
int stu::setnum(int num)
{
	m_num=num;
	return 0;
}
int stu::setyear(int year)
{
	m_year=year;
	return 0;
}
int stu::getyear()
{
	return m_year;
}
char* stu::getname()
{
	return m_name;
}
int stu::setname(char name[25])
{
	strcpy(m_name,name);
	return 0;
}

int main()
{
	stu y;
	int i=-1;
	int num,year;
	
	cin>>num;
	num=y.setnum(num);
	cout<<"m_num is"<<y.getnum()<<endl;
	
	cin>>year;
	year=y.setyear(year);
	cout<<"m_year is"<<y.getyear()<<endl;
	
	char name[]="小元";
	i=y.setname(name);
	cout<<"m_name is"<<y.getname()<<endl;
	return 0;
}

 このインスタンスで実行されるコードは次のようになります。

この例では、y オブジェクトを定義し、その y オブジェクトを参照してクラス内のメンバー関数とデータを参照し、y を参照して m_num、m_name[25]、m_year、クラス内の getnum()、setnum(int num)、getyear()、int setname(char name[25])、char* getname()、およびクラス内のその他のデータ型。

 1.2 コンストラクター

1.2.1 コンストラクターの概要

クラスのインスタンスがスコープに入ると、つまりオブジェクトが作成されると、プログラムによってコンストラクターが呼び出されます。コンストラクターの機能は、データに値を割り当てるなど、オブジェクトを初期化することです。メンバーやクラスのプロパティの設定など、これらの操作はコンストラクター内で行われます。

クラスのコンストラクターにはパラメーターを含めることができますが、パラメーターは存在する場合と存在しない場合があります。具体的な実装は次のとおりです。

class person
{
	public:
		int m_number;
		char m_name[128];
		person()	//无参构造函数对数据进行初始化 
		{
			m_number=10;
			cin>>m_name;
		}
		person(int num,char name)		//有参构造函数 
		{
			m_number=num;
			strcpy(m_name,name);	
		} 
};

 コンストラクターを使用するコードは次のとおりです。

#include<iostream> 
#include<string.h>
using namespace std;

class person
{
	public:
		int m_number;
		char m_name[128];
		person()	//无参构造函数对数据进行初始化 
		{
			cout<<"请输入号码:"; 
			cin>>m_number;
			cout<<"请输入姓名:";
			cin>>m_name;
		}
		person(int num,char name[128])		//有参构造函数 
		{
			m_number=num;
			strcpy(m_name,name);	
		} 
		int getnum()
		{
			return m_number;
		}
		char* getname()
		{
			return m_name;
		}
};

int main()
{
	person p;
	cout<<"num is "<<p.getnum()<<endl;
	cout<<"name is "<<p.getname()<<endl;
	person t(30,"小侯");
	cout<<"num is "<<t.getnum()<<endl;
	cout<<"name is "<<t.getname()<<endl;
	return 0;
}

特定の操作後の結果は次のようになります。

プログラム内で 2 つのオブジェクト p と t が宣言されており、p はデフォルトのコンストラクターで初期化され、t はパラメーター付きコンストラクターで初期化されるため、同じクラスのメンバー関数を呼び出した結果は異なります。

 

1.2.2 コピーコンストラクター 

後続の実行プロセスでオブジェクトの状態を復元するために、開発プログラムにオブジェクトのコピーを保存することが必要になる場合があります。オブジェクトの状態を復元するには、コピー コンストラクターを使用して、既に初期化されたオブジェクトに対して同一のオブジェクトを生成できます。コピー コンストラクターがコンパイラーによって呼び出され、同じクラスに基づく他のオブジェクトの構築と初期化が完了すると、その仮パラメータのみが参照である必要があります。

コピーコンストラクターの適用

#include<iostream>
#include<string.h>
using namespace std;

class phone
{
	public:
		char speak[128];
		phone(char spoken[128])
		{
			strcpy(speak,spoken);
		}
		phone(phone & copyp1)	//复制构造函数 
		{
			strcpy(speak,copyp1.speak);
		}
		char *speaker()
		{
			return speak;
		}
		int fix()
		{
			char name[28];
			cin>>name;
			strcpy(speak,name);
			cout<<"fixname is "<<speak<<endl;
			return 0;
		}
};

int main()
{
	phone p1("李牧歌");
	phone p2(p1);    //将对象p1的内容复制给p2
	cout <<"name is "<<p1.speaker()<<endl;
	cout<<"name is "<<p2.speaker()<<endl;
	p1.fix(); 
	return 0; 
}

プログラムを実行するには、まずパラメーター化されたコンストラクターで p1 を宣言し、次に、コピー コンストラクターを通じて p2 を宣言します (p1 はすでに初期化されたクラス オブジェクトであり、コピー コンストラクターのパラメーターとして使用できるため)。 2 つのオブジェクトが同じであること。

操作の結果は次のようになります。

 1.3 デストラクタ

コンストラクターとデストラクターは、クラス本体定義内の 2 つの特別なメンバー関数であり、どちらも値を返しません。コンストラクタ名識別子はクラス名識別子と同じであり、デストラクタ名識別子はクラス名識別子の前に「~」記号を追加します。

オブジェクトの作成直後にコンストラクターを使用してオブジェクト内の一部のデータ メンバーに値を割り当てる限り、主な目的はオブジェクトを初期化することです。デストラクターの主な機能はオブジェクトを解放することであり、オブジェクトが削除される前は、デストラクターとコンストラクターはまったく逆になります。

 デストラクターの使用

#include<iostream>
#include<string.h>
using namespace std;

class stu
{
	public:
		int m_num;
		stu();
		~stu();	//析构函数	
		int get();	
		char* m_pass;
};

stu::stu()
{
	cout<<"请输入学生的学号:"<<endl;
	cin>>m_num;
	m_pass=new char[128];
}
stu::~stu()		
{
	delete[] m_pass;	//删除m_pass的内容 
	m_num=0;
}
int stu::get()
{
	cout<<"学号是:"<<m_num<<endl;
	strcpy(m_pass,"恭喜你通过了!");
	cout<<m_pass<<endl;
	return 0;
}

int main()
{
	stu s;
	s.get();
	return 0;
}

プログラムは次の図のように実行されます。

プログラムはコンストラクターで new を使用してメンバー m_pass にスペースを割り当て、デストラクターで delete を使用して new によって割り当てられたスペースを解放します。メンバ m_pass は文字ポインタであり、文字ポインタが指す内容が get 関数に出力されます。

 デストラクターを使用する際の注意事項:

(1) クラス内に定義できるデストラクタは 1 つだけです。

(2) デストラクタはオーバーロードできません。

(3) コンストラクターとデストラクターは、キーワード void を追加せずに return ステートメントを使用して値を返すことはできません。

コンストラクターとデストラクターの呼び出し環境

(1) 自動変数のスコープはあるモジュールであり、モジュールの起動時には自動変数がコンストラクタを呼び出し、モジュールの終了時にはデストラクタが呼び出されます。 

(2) グローバル変数は main() 関数に入る前にコンストラクタを呼び出し、プログラムの終了時にデストラクタを呼び出します。

(3) 動的に割り当てられたオブジェクトは、nre を使用してオブジェクトにメモリを割り当てるときにコンストラクターを呼び出し、delete を使用してオブジェクトを削除するときにデストラクターを呼び出します。

(4) 一時変数は、計算をサポートするためにコンパイラによって自動的に生成されます。コンストラクターとデストラクターは、一時変数の有効期間の開始時と終了時に呼び出されます。

1.4 クラスメンバー

1.4.1 クラスメンバーへのアクセス

クラスの 3 つの大きな特徴として「カプセル化」があり、クラス内にカプセル化されたデータを外部から見えるか見えないかを設定できます。public、private、および protected のキーワードを使用して、クラス内のデータ メンバーが外部から見えるか見えないか、つまり、他のクラスがデータ メンバーにアクセスできるかどうかを設定できます。

キーワード public、private、および protected は、クラス メンバーが public、private、または protected であるかどうかを示します。この 3 つのキーワードによりクラスは 3 つの領域に分割され、パブリック領域のクラスメンバーにはクラスのスコープ外からアクセスできますが、プライベート領域とプロテクト領域はクラスのスコープ内でのみアクセスできます。

プライベート領域に外部クラスからアクセスする場合はフレンドを使用する必要があり、保護領域には派生クラスからアクセスできます。 

クラスにキーワードが追加されていない場合、システムのデフォルト状態のクラス メンバーはすべてプライベート領域にあります。

具体的な設定は以下のとおりです。

class basket
{
	private:
		int num;
	public:
		int getnum() {return num};
		int setnum(){num=15 retrun 0;};	
}; 

この設定では、num には外部からアクセスできませんが、num の値には外部からアクセスでき、共有関数を通じて num に対する特定の操作を実行できます。

さまざまな領域を使用して、開発者は要件に応じてカプセル化し、プライベート領域と保護領域内の他のクラスからアクセスおよび呼び出されたくないクラス メンバーを定義できます。これにより、クラス メンバーの隠蔽が保証されます。

各リージョンの終了は、次のリージョンが表示されるまで待機します。

 1.4.2 インラインメンバー関数

関数を定義する場合、inline キーワードを使用して関数をインライン関数として定義できます。クラスのメンバー関数を定義する場合、inline キーワードを使用してメンバー関数をインライン メンバー関数として定義することもできます。実際、メンバー関数の場合、定義がクラス本体にある場合。inline キーワードを指定しない場合でも、メンバー関数はインライン メンバー関数のままです。例えば

class basket
{
	private:
		int num;
	private:
		inline int getnum()const;	//定义一个内联成员函数 
		int setnum();	
}; 
int basket::getnum()const
{
	return num;
}
int basket::setnum()
{
	cin>>num;
}

class basket
{
	private:
		int num;
	private:
	int getnum()const;	//定义一个成员函数 
		int setnum();	
}; 
inline int basket::getnum()const	//函数为内联成员函数 
{
	return num;
}
int basket::setnum()
{
	cin>>num;
}

上記のコードはそれぞれ、クラス本体内にインライン メンバー関数を定義し、クラス本体の外にインライン メンバー関数を定義しています。

プログラム内のコードは、inline キーワードを使用して inline 関数を呼び出す必要がある場所を示しています。インライン関数の場合、プログラムは関数を呼び出す場所に関数のコードを直接挿入します。関数本体に多くのステートメントがある場合、プログラム コードは拡張されます。クラスのデストラクターがインラインとして定義されている場合は、プログラム コードが拡張されます。機能を使用すると、コードが肥大化する可能性があります。

連結関数では次の点に注意する必要があります。

(1) インラインメンバー関数ではループと switch ステートメントは使用できません。

(2) インライン関数の定義は、最初の呼び出しの前に指定する必要があります。

インライン関数と他の関数の違いは、関数が呼び出されると、プログラムは実行のために関数本体にジャンプし、実行が完了すると、その関数を呼び出したステートメントに戻るのに対し、インライン関数はインライン関数としての呼び出しの式 置き換える本体。呼び出しステートメントでコードを書き直すのと同様です。

1.4.3 静的クラスのメンバー

このセクションの前で定義されたクラス メンバーはすべて、クラス名を介して直接アクセスされるのではなく、オブジェクトを介してアクセスされます。クラスメンバーが静的クラスメンバーとして定義されている場合、クラス名を使用した直接アクセスが許可されます。静的クラス メンバーは、クラス メンバー定義の前に static キーワードを使用して識別されます。例えば

クラスCブック

{

公共:

        静的 int m_price;

}; 

静的データ メンバーを定義する場合、通常はクラス本体の外側で静的データ メンバーを初期化する必要があります。例えば

int Cbook::m_price=10; 

静的データ メンバーの場合、オブジェクトを通じてアクセスできるだけでなく、クラス名を直接使用してアクセスすることもできます。例えば

int main()

{

        Cbook book; //Cbook クラスのオブジェクト book を定義します 

        cout<<Cbook::m_price<<endl; //クラス名で静的メンバーにアクセス 

        cout<<book.m_price<<endl; //オブジェクトを通じて静的メンバーにアクセス

        0を返します。

}

クラスでは、静的データ メンバーはすべてのクラス オブジェクトで共有され、1 つのオブジェクトの静的メンバーが変更されると、残りの静的メンバーも変更されます。

静的データメンバーの場合は、次の点にも注意する必要があります。

静的データ メンバーは現在のクラスの型にすることができますが、他のデータ メンバーは現在のクラスのポインターまたは参照型のみにすることができます。

class Cbook
{
	public:
		static int m_price;
		Cbook m_book 	//非法的定义,不允许在类中定义所属类的对象
		static Cbook m_Vcbook 	//正确静态数据成员允许定义所属类的对象
		Cbook *m_pbook;		//正确可以是指针或引用的类型	
}; 

静的データメンバはメンバ関数のデフォルトパラメータとして使用できます(通常のメンバ関数はデフォルトパラメータとして使用できず、パラメータに代入することもできません)

class Cbook
{
	public:
		static int m_price;	//定义一个静态数据成员 
		int m_num;
		void output(int data=m_price)	//定义一个函数,将静态数据作为默认参数 
		{
			cout<<data<<endl;
		} 
		void ouputnum(int num=m_num)	//错误的定义,类的普通成员不能作为默认参数
		{	
			cout<<num<<endl;
		}	 
}; 

 クラスの静的メンバー関数は、通常のデータ メンバーではなく、クラスの静的データ メンバーにのみアクセスできます。

class Cbook
{
	public:
		static int m_price;	//定义一个静态数据成员 
		int m_num;
		static void output()	//定义一个静态成员函数
		{
			cout<<m_price<<endl;	//可以访问静态数据成员
			cout<<m_num<<endl;		//错误,静态函数只能访问静态成员 
		} 
}; 

さらに、静的メンバー関数を const 関数として定義することはできません。つまり、静的メンバー関数の最後に const キーワードを使用することはできません。たとえば、次の静的メンバー関数は不正です。

静的 void 出力()const;

静的データメンバ関数を定義する場合、関数の実装コードがクラス本体の外にある場合、実装部分に static キーワードを追加する必要はありません。追加しないと不正な動作が発生します。 

 上の写真にあるように、このブログはまずここで終わります。人生は道路を巡る旅のようなもので、私も歩行者です。人生という道を一緒に歩んでくれる人はなかなかいないので、やっていることが違うからと不安にならずに、それぞれの分野で探求を続けていただければと思います。

おすすめ

転載: blog.csdn.net/m0_61886762/article/details/124854684