[C ++クラスとオブジェクト1]-コンストラクタとデストラクタ

コンストラクタとデストラクタに関しては、それらが何で、何をしているのか知っていますか?まず、oopのアイデアを使用して、シーケンシャルスタックをシミュレーションおよび実装します。コードは次のように実装されます。

class SeqStack
{
public:
	//对象成员变量的初始化操作
	void init(int size = 10)
	{
		_pstack = new int[size];
		_top = -1;
		_size = size;
	} 

	//释放对象成员变量占用的外部堆内存(外部资源)
	void release()
	{
		delete[] _pstack;
		_pstack = nullptr;
	}
	void push(int val)
	{
		if (full())
			resize();
		_pstack[++_top] = val;
	}
	void pop()
	{
		if (empty())
			return;
		--_top;
	}
	int top()
	{
		return _pstack[_top];
	}
	bool empty() { return _top == -1; }
	bool full() { return _top == _size - 1; }
private:
	int* _pstack;//动态开辟数组,存储顺序栈的元素
	int _top;//指向栈顶元素的位置
	int _size;//数组扩容的总大小
	void resize()
	{
		int* ptmp = new int[_size * 2];
		for (int i = 0; i < _size; ++i)
		{
			ptmp[i] = _pstack[i];
		}
		delete[]_pstack;
		_pstack = ptmp;
		_size *= 2;
	}
};
int main()
{
	SeqStack s;
	s.init(5);
	for (int i = 0; i < 15; ++i)
	{
		s.push(rand() % 100);
	}
	while (!s.empty())
	{
		cout << s.top() << " ";
		s.pop();
	}
	return 0;
}

結果は次のとおりです。
ここに画像の説明を挿入
しかし、一見完璧なコードの後に​​は、多くの問題があります。多くのメンバーメソッドに直面すると、たとえば、releaseメソッドは完全に忘れられたなど、作成した内容を忘れることもあります。注意深く考えると、ヒープ上で開かれているメモリが解放されていないため、プログラムがクラッシュする可能性があります。したがって、オブジェクトを手動で初期化し、オブジェクトのリソースを解放する必要があるたびに、この問題を解決する良い方法はありますか?これから、コンストラクターとデストラクターの概念を紹介します。

1.コンストラクタとデストラクタとは

コンストラクタとデストラクタの名前はクラス名とは異なり、戻り値はありません。

1.定義

コンストラクター:主に、作成時にオブジェクトを初期化するために、つまりオブジェクトメンバー変数に初期値を割り当てるために使用され、常に新しい演算子と共にオブジェクトを作成するステートメントで使用されます。
あるパラメータを持つ可能、それはコンストラクタ、複数設けることが可能であるINITとして再装填、および機能を、完成したオブジェクトのコンストラクタへの呼び出しが生成されます

SeqStack(int size = 10)
	{
		cout << this << "SeqStack()" << endl;
		_pstack = new int[size];
		_top = -1;
		_size = size;
	}

デストラクタ:コンストラクタとは異なり、オブジェクトがそのライフサイクルを終了するときに、オブジェクトが配置されている関数が呼び出された場合、システムは自動的にデストラクタを実行します。**デストラクタはオーバーロードできません。パラメータがないため、デストラクタを呼び出すことができるのは、スコープが外れ、オブジェクトが存在しない場合のみです。

~SeqStack()
	{
		cout << this << "~SeqStack()" << endl;
		delete[] _pstack;
		_pstack = nullptr;
	}

2.注意点

1.コンストラクターの呼び出しはオブジェクトを使用できず、受信パラメーターに従って一致します

2. 最初に構築し、次に破棄してから、最初に構築します。
たとえば、上記のコードでは、main関数に別のオブジェクトを追加します。コードの実装は次のとおりです。

int main()
{
	SeqStack s;
	for (int i = 0; i < 15; ++i)
	{
		s.push(rand() % 100);
	}
	while (!s.empty())
	{
		cout << s.top() << " ";
		s.pop();
	}
	SeqStack s1(50);
	return 0;
}

結果は次のとおりです
ここに画像の説明を挿入
。最初に構築されたsオブジェクトが最後に破棄されることがわかります。

3.システムはデフォルトでパラメータなしのコンストラクタとデストラクタを生成します使用されるクラスが外部スペースを占有しない場合、デストラクタを自分で定義する必要はありません。

4. デストラクタが呼び出される前にオブジェクトが消えていないため、デストラクタの呼び出しにオブジェクトを含めることができます

5.ただし、オブジェクトに従ってデストラクタを呼び出すと、現時点でヒープメモリへの不正アクセスが発生するため、自分でデストラクタを呼び出すことはお勧めしません。
これらの2行のコードを実行するなどs1。〜SeqStack(); s1.push(30);
分析は次のとおりです。
ここに画像の説明を挿入

第二に、コンストラクタの初期化リスト

1.商品クラスを実装する

商品クラスを定義する場合、コードは次のようになります。

class CGoods
{
public:
	CGoods(const char* n, int a, double p)
	{
		strcpy(_name, n);
		_amount = a;
		_price = p;
	}
	void show()
	{
		cout << "name: " << _name << endl;
		cout << "amount:" << _amount << endl;
		cout << "price:" << _price << endl;
		_data.show();
	}
private:
	char _name[20];
	int _amount;
	double _price;
};

しかし、これに基づいて、次のように商品日付情報を追加したいと思います。

class CDate
{
public:
	CDate(int y, int m, int d)
	{
		_year = y;
		_month = m;
		_day = d;
	}
	void show()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

日付は製品情報の一部です... 2つの部分を組み合わせる方法は?

メンバーオブジェクトは次のように使用します:
CDate _dataを追加します; CGoodsクラスプライベートのメンバーオブジェクト。

しかし、これでは十分ではありません。コンパイルは、CDateに適切なデフォルトのコンストラクターがないことを示すエラーを報告します

オブジェクトの生成はメモリの割り当てとコンストラクターの呼び出しの2つの部分に分かれていることは誰もが知っているためです。コンストラクターを指定しない場合、コンパイラーはデフォルトのコンストラクターを呼び出しますが、既にコンストラクターがあるため、生成されません。デフォルトのコンストラクタ。したがって、上記のコンストラクタを改善する必要があります。改善されたコードは次のとおりです。

CGoods(const char* n, int a, double p,int y,int m,int d)
		:_data(y,m,d)
	{
		//当前类类型构造函数体
		strcpy(_name, n);
		_amount = a;
		_price = p;
	}

この方法でデータの構築メソッドを指定します。コンストラクターの初期化リストとも呼ばれます。現在のオブジェクトメンバー変数の初期化メソッドを指定できます(特にメンバーオブジェクトの場合)。

2.コンストラクターの初期化リストと現在のクラス型のコンストラクター本体の違い

一般に、メンバー変数_amoutを取ります

  • コンストラクタの初期化リストは、変数が定義されたときの変数の初期化と同等であり、int _amount = aと同様です。
  • クラス型のコンストラクタ本体は、int _amount; int _amount = a;と同等です。

ただし、一般的な型の場合は逆アセンブリの違いはありませんが、クラス型の初期化リストに書き込む必要がある
ため、商品クラスのコンストラクターを次のように変更することもできます。

CGoods(char* n, int a, double p, int y, int m, int d)
	:_data(y, m, d)//CData _data(y,m,d);
	,_amount(a)
	,_price(p)
{
	strcpy(_name, n);
}

3.コンストラクターの初期化リストの演習

次のコード、実行結果は何ですか?

class Test
{
public:
	Test(int data = 10):mb(data),ma(mb){}
	void show()
	{
		cout << "ma:" << ma << " mb:" << mb<<endl;
	}
private:
	int ma;
	int mb;
};
int main()
{
	Test t;
	t.show();
	return 0;
}

結果は次のとおりです。
ここに画像の説明を挿入
理由:VSコンパイラーでは、スタックの開発は0xcccccccc = -858993460に初期化されます。オブジェクトが生成されると、オブジェクトのメンバー変数の初期化メソッドは、それらが定義された順序に関連し、コンストラクター初期化リストに含まれます出現順序は関係ありません

3.さまざまなオブジェクトのライフサイクル

1.スタック上のローカルオブジェクト:コンストラクターが定義されているときにコンストラクターを呼び出し、関数スコープの外でデストラクターを呼び出します。たとえば、上記のコードが実装されています。

2.スタック上のグローバルオブジェクト(.dataセクション):コンストラクターが定義されているときにコンストラクターを呼び出し、プログラムが終了したときにのみコンストラクターを破壊します。
たとえば、上記のコードプロトタイプで、グローバルオブジェクトgsを追加します。彼の構築デストラクタ呼び出しは次のとおりです。
ここに画像の説明を挿入

3.ヒープ上のオブジェクト:定義されている場合:①。Mallocがメモリを開く②。構築を呼び出す;解放された場合:①。デストラクタを呼び出す②。次に、メモリを解放する
たとえば、上記のコードプロトタイプでは、オブジェクトpsをヒープに追加します。彼の構築デストラクタ呼び出しは次のとおりです。

SeqStack* ps = new SeqStack(60);//开辟在(.heap)段里面malloc内存开辟+SeqStack(60)对象构造操作
	ps->push(70);
	ps->push(80);
	ps->pop();
	cout << ps->top() << endl;
	delete ps;

操作の結果によると、
ヒープ上のオブジェクトは手動で解放する必要があるため(最初にps->〜SeqStack()を呼び出し、次に解放(ps))、彼は破壊せずに構築しているだけであることがわかります。

公開された98元の記事 ウォンの賞賛9 ビュー3673

おすすめ

転載: blog.csdn.net/qq_43412060/article/details/105065123