c++基礎知識--クラスのレプリケーション制御

4590 ワード

引用:よく見かける面接問題で、既知のStringの原型は:
class String{public:String(const char*str=NULL);//一般コンストラクション関数String(const String&other);//コンストラクション関数をコピー~String(void);//コンストラクション関数String&operate=(const String&other)//リロード値オペレータprivate:char*m_data;
}; 上記Stringの4つの関数を実装してください.
この問題は,タイプのレプリケーションコンストラクタ,付与オペレータ,および解析関数の実装に関し,注意すべき点がたくさんある.c++primer 13章参照
1.コンストラクタのコピー
これは、新しいオブジェクトを定義し、銅タイプのオブジェクトで初期化すると、表示される呼び出しが構造関数をコピーし、そのタイプのオブジェクトを関数に渡すか、関数からそのタイプのオブジェクトを返すと、暗黙的な呼び出しが構造関数をコピーする特殊な構造関数です.
a.なぜ形参は参照しなければならないのですか.次のコードを考慮します.
class A
{
private:
int value;
public:
A(int n){value=n;}
A(A other){value=other.value;}
void functionA(){};
~A(){}
};
int main(void)
{
A a = 10;
A b = a;
b.functionA();

}

通常、このコードはコンパイルエラーを表示し、コンパイル実行が可能であると仮定すると、A(A other)は値伝達であるため、A b=aを実行すると、A(A other)が呼び出され、aが実パラメータ(暗黙呼び出しA(A other))に形パラメータとしてコピーされ、すなわち、レプリケーション構造関数で構造関数が呼び出され、無条件再帰を形成する.したがって、C++規格では、レプリケーション構造関数が値伝達されることは許されません.正しい形式は:A(const A&other).
b.レプリケーションコンストラクタをカスタマイズする必要があるのはいつですか?
レプリケーションコンストラクション関数を定義していない場合、コンパイラは他のコンストラクション関数を定義しても、デフォルトの動作はメンバーごとに元のオブジェクトのコピーに初期化されます.
クラスにポインタがある場合、またはメンバーが構築時に他のリソースを割り当てる必要がある場合は、通常、レプリケーション構造関数を定義する必要があります.これには、オブジェクトの深いコピーと浅いコピーが含まれています.クラスがchar*strのような文字配列を指すリソースを持っている場合、クラスのオブジェクトがコピープロセスを起こすと、リソースが再割り当てされます(B:str=new char[length+1];if(str!=NULL);strcpy(str,A.str);),このプロセスは深いコピーであり、逆に、リソースを再割り当てしていない(B:str=A.str)、浅いコピーである.
クラスがレプリケーションを禁止する場合は、レプリケーション構造関数(privateとして宣言)を定義する必要があります.
以上より、Stringのレプリケーションコンストラクタは次のように定義できます.
String::String(const String& other)
{
      int length = strlen(other.m_data);
      m_data = new char[length+1]; //  '\0'
      strcpy(m_data, other.m_data);    
}

 
 
2.代入オペレータの再ロード
割り当てオペレータは、this(非表示)と同じタイプのオブジェクトのconst参照をパラメータとして使用します.同じタイプの参照を返します.通常、クラス定義レプリケーションコンストラクタは、割り当てオペレータを定義する必要があります.
a.値を割り当てる前に、現在のオブジェクトのリソースを解放する必要があります.そうしないと、メモリの漏洩が発生します.また、その前に、入力されたパラメータと現在のオブジェクトが同じインスタンスであるかどうかを判断する必要があります.そうしないとdeleteで重大なエラーが発生します.
String& String::operator=(const String& other)
{
if(this == &other)
{
return *this;
}
delete[] m_data;
int length = strlen(other.m_data);
m_data  = new char[lenght+1];
if(m_data != NULL)
{
strcpy(m_data,other.m_data);
}
return *this;
}
//           ,     

3.構造関数a.オブジェクトを消すときに構造関数が呼び出されます.動的に割り当てられたオブジェクトの場合、オブジェクトへのポインタが削除された場合にのみ取り消されます.構造関数は、通常、構造関数またはオブジェクトのライフサイクル内に取得されたリソースを解放します.
b.クラスで宣言された順序の逆順序でメンバーを取り消すデフォルトの構造関数(コンパイラは常に生成されます).ただし、デフォルトの構造関数はポインタが指すオブジェクトを削除しません.
c.構造関数には戻り値がなく、パラメータがないため、再ロードできません.
String::~String()
{
delete [] mdata;
}

後述:通常、この3つのレプリケーション制御メンバーのうち1つを定義する場合は、いわゆる「rule of three」という2つを定義する必要があります.