条項05:C++が黙々と作成して呼び出す関数を理解する

3849 ワード

各classには、1つ以上のコンストラクション関数、1つのコンストラクション関数、1つのcopy assignmentオペレータがあります.これらは、新しいオブジェクトを生成し、初期化され、古いオブジェクトから解放され、適切にクリーンアップされ、オブジェクトに新しい値が与えられるように、基礎的な操作を制御します.
では、empty classを作成したとき、コンパイラのコードを使用して処理すると、empty classではありません.コンパイラは、defaultコンストラクション関数、1つの解析関数、1つのcopyコンストラクション関数、1つのcopy assignmentオペレータをこっそり生成し、それらはすべてinline(暗黙的なinline)です.次のコード例
     : class empty{}; 

次のコードに等しくなります.
class Empty { 
public:
Empty() { }//default     

~Empty() { }//    
Empty(const Empty& rhs) { }//copy    
Empty& operator=(const Empty& rhs) { }//copy assignment   
}; 

注意:上のリロードされた操作演算子operator=の戻り値はオブジェクトの参照であり、条項21はオブジェクトの参照を返すことを妄想しないでくださいと言っているようです.この文章の意味は、オブジェクトの参照を返すことができないということではなく、オブジェクトの参照を返すときに、参照の本体が誰であるかを確定し、合理的にdeleteされるかどうかを意味します.
この4つの名詞の概念はそれぞれ次のとおりです.
defaultコンストラクション関数:コンストラクション関数を提供しない場合、システムはパラメータを持たず、関数コードを含まないコンストラクション関数を与えます.しかし、コンストラクション関数を宣言すると、コンパイラはdefaultコンストラクション関数を作成しません.
構造関数:構造関数とは逆に、オブジェクトがその役割ドメインから離れた場合(たとえば、オブジェクトが存在する関数が呼び出された場合)、システムは自動的に構造関数を実行します.構造関数は、オブジェクトの作成時にnewでメモリ領域を開き、終了する前に構造関数でdeleteで解放するなど、「後始末」の作業に使用されることが多い.
copyコンストラクション関数:単一のコンストラクションのみであり、このコンストラクション関数がコンストラクション関数(C++pirmer定義)となるように、このクラスタイプのオブジェクトへの参照です(const修飾が一般的です).X(const X&)と呼ばれることが多く、コンパイルによって自動的に呼び出される.
 
copy assignmentオペレータ:自動合成の付与オペレータ.
 
copyコンストラクション関数が呼び出されるのはいつですか
次の3つのケースが発生すると、クラスのコピーコンストラクション関数が呼び出されます.1)インスタンス化されたクラスオブジェクトを使用して、クラスの別のオブジェクトをインスタンス化します.2)このクラスのオブジェクトを1つの関数のパラメータとして伝達する.3)関数の戻り値がクラスのオブジェクトです.
 
コンパイラはcopyコンストラクション関数が必要(呼び出される)場合、copyコンストラクション関数はコンパイラによって作成されますが、コンパイラが生成したコンストラクション関数はnon-virtualであり、このclassのbase class自身がvirtualコンストラクション関数(この場合、この関数は虚属性)を宣言しない限り注意してください.
 
copy assignmentオペレータはいつ自動的に呼び出されませんか?
 
copyコンストラクション関数とcopy assignmentオペレータについては、コンパイラが作成したバージョンは、ソースオブジェクトのnon-staticメンバー変数を単純にターゲットオブジェクトにコピーするだけです.ただし、コンパイラはcopy assignmentオペレータ関数の生成を拒否する場合があります.たとえば、参照メンバーとconstメンバーが存在します.引用の変更について、つまり引用自体を変更することができますか?もしそうであれば、C++の原則に反します.参照はオブジェクトを変更できません.したがって、copy assignmentオペレータを自分で定義する必要があります.しかし、copyコンストラクション関数については、オブジェクト内の参照やconstメンバーが初期化されていないため、この心配はありません.たとえば、次のコードがあります.
#include <iostream>  
  
using namespace std;  
  
class Person 
{  
public:  
  
    Person(string& a, const int& b) : name(a), id(b) { }  
  
private:  
  
    const int id;  
    string& name;  
  
};  
  
int main() 
{  
    Person p1(string("chu"), 1);  
  
    Person p2(string("jun"), 2);  
  
    p1 = p2;/////// error C2582: 'operator =' function is unavailable in 'Person'  
  
    system("pause");  
  
    return 0;  
} 

コンパイラがderived classesで生成されたcopy assignmentオペレータがbase class成分を処理するため、ベースクラスがcopy assignmentをprivateとして宣言すると、派生タイプはコンパイラの助けを得ることができません.派生タイプは、ベースタイプのcopy assignment関数を呼び出すことができません(アクセス権がありません).
#include <iostream>

using namespace std;

class BaseClass 
{

private:

    BaseClass& operator=(const BaseClass& rhs) { }

};


class derived : public BaseClass { };


int main() 
{

    BaseClass px1, px2;

    px1 = px2; ///// 'BaseClass::operator =' : cannot access private member declared in class 'BaseClass'

    system("pause");
    return 0;

}  

だから、覚えておいてください.
コンパイラはclassのdefaultコンストラクション関数、copyコンストラクション関数、copy assignmentオペレータ、およびコンストラクション関数を暗黙的に作成できます.