C++学習5:ポインタ付きクラスの詳細(侯捷Stringクラスを例に)

12548 ワード

ポインタを持たないクラスと同様に、防衛式声明、前置声明が必要です.次に、クラスの定義、関数(メンバー関数とグローバル関数)の宣言と定義を行います.この部分の基本フレームワークは、ポインタを持たないクラスと同じです.参考:C++学習4:ポインタを持たないクラス(侯捷Complexクラスを例に)について詳しく説明します.次に、違いについて分析します.
1コード部
1.1 main関数
ポインタを持たないクラスとの主な違いを明確にするには、main関数を直接見てください.
int main()
{
	String s1();
	String s2("hello");

	String s3(s1);		//     ,    :    
	cout << s3 << endl;

	s3 = s2;			//     ,    :    
	cout << s3 << endl;
}

ここでは、コピー構造、コピー付与の2つの主要な操作があります.その仕事はとても简単です:1つのbit 1つのbitのコピーと付与を行って、Complexクラスの中で定义がなくて、この时コンパイラはそれにセットをあげて、だからもあります.デフォルトのコピーポインタセットは、単純に1つの位置を指しているだけで、本当の構造ではないので、問題が発生します.だからデフォルトのバージョンは必ずしも十分ではありません.効果は私たちが望んでいるものではありません.
したがって、クラスにポインタがある限り、コピー構造とコピー付与操作を自分で書かなければなりません.
1.2クラスの定義
class String
{
public:
	String(const char* cstr = 0);			//    
	String(const String& str);				//       -> 1
	String& operator= (const String& str);	//       -> 2
	~String();								//     -> 3
	char* get_c_str() const { return m_data; }

private:
	char* m_data;
};

設計案:文字列のサイズが不明なため、文字列にポインタを持たせ、メモリが必要なときに作成します.この動的な割り当ての方法はもっとよくて、これとポインタをprivateの中に置いてください.get_c_str()関数:charタイプのポインタを返し、このクラスのデータを変更しません.だからconstをつけた(詳しくは一番上のリンクを参照).Big Three:1、コピーコンストラクタ:まずコンストラクタで、自分のタイプ名を関数として戻り値はありません.しかし、彼は自分のタイプと同じものを受け入れています.この例のようにパラメータもStringタイプで、これがコピーコンストラクタです.2、コピーコンストラクタ:賦値オペレータをリロードすることで、賦値の操作であることがわかります.彼が受けているのも自分と同じタイプのものです.この例では、パラメータもStringタイプであり、コピー割り当てです.3、構造関数:このクラスのオブジェクトが死亡した場合(役割ドメインを離れる場合など)、呼び出されます.
1.3関数の定義
inline
String::String(const char* cstr = 0)//      ,      0,      0
{
	if (cstr)
	{
		m_data = new char[strlen(cstr) + 1];
		strcpy(m_data, cstr);
	}
	else
	{
		m_data = new char[1];
		*m_data = '\0';
	}
}
inline
String::~String()//    
{
	delete[] m_data;
}
inline
String& String::operator=(const String& str)//    ,           this
{
	if (this == &str)//&            ,    (&     )
		return *this;
	delete[] m_data;
	m_data = new char[strlen(str.m_data) + 1];
	strcpy(m_data, str.m_data);

	return *this;
}

ostream& operator<<(ostream& os, const String& str)
{
	os << str.get_c_str();
	return os;
}

以上がすべての定義です.構造関数があれば構造関数があることに注意してください.プロファイル処理は次の例で行われます(ここでは、新しい作成方法もあります).
{
	String s2("hello");
	String *p = new String("world");
	delete p;
}	

s 2は括弧を離れると自動的に構造関数~String()が呼び出されるが,ここではdeleteがpを落とす必要がある.具体的なdeleteの原因は本稿の第3部を参照してください.
2クラスのポインタにはcopy_が必要ですctorとcopy_op=の原因
String s2(s1);//s2       ,     ,      
String s2 = s1;//s2   ,  s1         s2,      

2.1コピー構造
以下の2つの文は、aというポインタが「hello」を指し、bというポインタが「world」を指すことを示す.デフォルトバージョンのコピーで値を割り当て、aが指す値をbに割り当てると、bit対bitの値に基づいて、bのポインタがaのポインタが指す位置を指す.
String a("hello");
String b("world");

この場合を「浅いコピー」と呼ぶことによる結果:1、「world」という位置のメモリ漏れ2、aとbは同じ位置を指し、ポインタaの操作に直接このメモリに影響し、bも影響を受ける.aが「HELLO」に変更されると、bも「HELLO」になり、「別名」現象が現れる.3、2つのポインタは1つのメモリを指し、freeが1つ落ちたら、もう1つが野ポインタになるのは危険です.
深いコピー:真のコピーを実現するには、前に定義したコピー構造とコピー付与です.
コピー構造:s 1を手本とし、s 1と同じs 2を構築し、異なるメモリ領域に配置します.
2.2コピー付与
割り当てられるメモリを空にし、割り当てられる内容と同じ大きさの空間を割り当て、最後に格納すべきものを格納します.1、自己賦課値を検出する(功力が深い);2、deleteから自分を落とす.3、空間を開く.4、最後にコピーする.