【C++】C++独学旅(8):構築関数と解析関数

14136 ワード

クラスという概念を新しく導入したので、突然いろいろな概念が多くなって面倒になるのは言うまでもありません.今日はコンストラクション関数とコンストラクション関数についてお話しします.
一、構造関数とコピー構造関数
  1. コンストラクタ
簡単に言えば、コンストラクション関数はクラスメンバーを初期化する関数です.では、どのように使いますか.コードに直接アクセスします.
 1 //    
 2 #include<iostream>
 3 using namespace std;
 4 class Date
 5 {
 6 public:
 7     int output();
 8     Date(int,int,int);
 9     Date();
10 private:
11     int year,month,day;
12 };
13 
14     Date::Date(int x, int y, int z):day(z)
15     {
16         year=x;
17         month=y;
18     }
19     Date::Date():year(1),month(1)
20     {
21         day=1;
22     }
23     int Date::output()
24     {
25         cout<<""<<year<<" "<<month<<" "<<day<<" "<<endl;
26     }
27     int main()
28     {
29         Date d1(1997,4,24);
30         Date d2;
31         Date d3;
32         d3=Date(2015,12,13);
33         d1.output();
34         d2.output();
35         d3.output();
36         return 0;
37     }

コードを見て話をして、重点の間違いやすい内容は円の番号で表示します:
8、9行目のDate(int,int,int)とDate(int)の2つの関数がコンストラクション関数であり、クラスタイプ名と同じであることがわかります.1コンストラクション関数名はクラスタイプ名と同じのみで、宣言時に関数タイプをマークできません(voidもマークできません).
14行目から23行目を見て、ここでは関数の定義で、関数が何をするかを明記しています.主に初期化賦値です.②定義時に関数タイプを表示することはできません.また、戻り値も指定できません.③コンストラクション関数は、パラメータがあってもなくてもよい.このウィジェットではここで関数リロードを用い,4コンストラクション関数でも関数リロードを用いることができ,呼び出すときに呼び出す方法によってどれであるかを決定する.コンストラクション関数を定義する際に、⑤変数に値を割り当てるには、パラメータテーブルのカッコの後の":"の後に変数(値)を書くか、一般的に関数体の間に書くかの2つの方法があり、実行の順序は初期化領域→関数体である.
次に、コンストラクション関数を呼び出す方法について説明します.コンストラクション関数は手動で呼び出す必要はなく、29行目から30行目が表示されます.⑥コンストラクション関数はクラス変数を定義するときに自動的に呼び出されます.呼び出すときは呼び出すときのパラメータテーブルのフォーマットに基づいて関数の重荷重のどれかを決定します.特に、変数を定義するときにパラメータのないコンストラクション関数を呼び出すときはカッコを付けないでください.つまり、30行は「Date d 2()」ではなく「Date d 2」です.また⑦既に定義宣言された変数にコンストラクション関数を再使用して値を付与する方法も32行目と同じで、注意等号右側は「Date(......)」であり、すなわち、タイプ名(......).
各クラスには少なくとも1つのコンストラクション関数が必要です.ユーザーがコンストラクション関数を記述していない場合、システムは自動的に1つを作成し、何もしないだけで、出力は文字化けしています.だから、ユーザーが自分で書く必要がありますよ.⑧ユーザーが自分で書いた構造関数があれば、呼び出し時に自分で作成したものを呼び出すことはありません.だから、呼び出し時のパラメータが間違っていると、直接ヒントになります.この関数を定義していません.
  2. コピーコンストラクタ
コピーコンストラクション関数は、既存のオブジェクトを使用して別の同じタイプのオブジェクトを初期化するために使用されます.固有のパラメータがあります.
  
 1 //      : 1.
 2 #include<iostream>
 3 using namespace std;
 4 class Date
 5 {
 6 public:
 7     int output();
 8     Date(int, int, int);  //    
 9     Date(Date &);  //      
10 private:
11     int year,month,day;
12 };
13 Date::Date(int x,int y,int z)
14 {
15     year=x;
16     month=y;
17     day=z;
18 }
19 Date::Date(Date &d)  //      
20 {
21     year=d.year+1;  //   year +1
22     month=d.month;
23     day=d.day;
24 }
25 int Date::output()
26 {
27     cout<<""<<year<<" "<<month<<" "<<day<<" "<<endl;
28 }
29 int main()
30 {
31     Date d1(2016,2,14);
32     Date d2(d1);
33     d1.output();
34     d2.output();
35 }

// :
:2016 2 14
:2017 2 14

コピーコンストラクタがd 2を初期化する際にd 1の初期化に関連していることがわかる.コピーコンストラクション関数は、次の3つの場合に呼び出されます.
①上記の例1のように、あるオブジェクトを別のオブジェクトで初期化する.
②1つのオブジェクトを値伝達で使用
// 2.
void
func(Date d) { date.output(); } int main() { Date d1(2015,6,7); func(d1); }

③1つのオブジェクトが値伝達で関数から戻る
// 3.
Date fun2() { Date d1(
2015,6,8); return d1; } int main() { fun2().output(); }

例2および例3では、ユーザーがカスタムコピー構造関数を持たないため、デフォルトのコピー構造関数を自動的に作成し、値を伝達するプロセスに使用します.
次に、浅いコピーと深いコピーについて説明します.
 1 // 4.
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 class student
 6 {
 7 public:
 8     student();
 9     void setname (char *n);
10     void outputname();
11 private:
12     char *name;
13 };
14 student::student()
15 {
16     name = new char[10];
17     if(name!=NULL)
18     {
19         strcpy(name,"XiaoMing");
20     }
21 }
22 void student::setname(char *n)
23 {
24     if(name!=NULL)
25     {
26         strcpy(name,n);
27     }
28 }
29 void student::outputname()
30 {
31     cout<<name<<endl;
32 }
33 
34 int main()
35 {
36     student s1,s2(s1);
37     cout<<"s1: ";
38     s1.outputname();
39     cout<<"s2: ";
40     s2.outputname();
41     s1.setname("Xiaoxin");
42     cout<<endl<<"After Change"<<endl;
43     cout<<"s1: ";
44     s1.outputname();
45     cout<<"s2: ";
46     s2.outputname();
47 }

結果は次のとおりです.
s1: XiaoMing
s2: XiaoMing

After Change
s1: Xiaoxin
s2: Xiaoxin

システムが自動的に作成するコピー構造関数は、s 2を自動的に新しく作成する空間を自動的に作成しないからである.nameポインタは新しい空間を指すので、s 2 nameの値はs 1の変更に伴って変更されます.2つのnameポインタは同じ空間を指しています.
カスタムコピーコンストラクション関数で深いコピーを使用すると、この問題を解決するために新しいスペースをカスタマイズできます.
 1 // 5.
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 class student
 6 {
 7 public:
 8     student();
 9     student(student &);
10     void setname (char *n);
11     void outputname();
12 private:
13     char *name;
14 };
15 student::student()
16 {
17     name = new char[10];
18     if(name!=NULL)
19     {
20         strcpy(name,"XiaoMing");
21     }
22 }
23 student::student(student &stu)
24 {
25     name = new char[10];
26     strcpy(name,stu.name);
27 }
28 void student::setname(char *n)
29 {
30     if(name!=NULL)
31     {
32         strcpy(name,n);
33     }
34 }
35 void student::outputname()
36 {
37     cout<<name<<endl;
38 }
39 
40 int main()
41 {
42     student s1,s2(s1);
43     cout<<"s1: ";
44     s1.outputname();
45     cout<<"s2: ";
46     s2.outputname();
47     s1.setname("Xiaoxin");
48     cout<<endl<<"After Change"<<endl;
49     cout<<"s1: ";
50     s1.outputname();
51     cout<<"s2: ";
52     s2.outputname();
53 }

これにより,各オブジェクトに独立したnameリソース空間があり,使用の混乱を回避できる.
 
二、構造関数
上記の例5から分かるように,newでnameの空間を作成し,オブジェクトの使用が完了して消滅すると,その作成された空間はdeleteで削除されず,このような空間が多く作成されるとメモリが重荷に耐えられなくなるが,使用済みのたびに手動で削除するのは面倒ではなく,大きな労力がかかる.構造関数は、オブジェクトが消滅した後に作成された空間を自動的に解放するために使用されます.使用方法:
//       “~  ”
public:
    ~student();

student::~student()
{
    delete name;
}

注意:1構造関数名は「~クラス名()」のみで、タイプも戻り値もありません.2クラスには1つの構造関数しかありません.ユーザーが作成していない場合、システムは自動的に1つの仕事をしないものを作成します.③解析関数は、対象がスコープを超えたときに自動的に実行されます.
  Over!