講義メモ

・p.171「デストラクタ」から再開します

アレンジ演習フォロー:p.169 construct02.cs

・名前と年齢を引数で受け取るコンストラクタ④を追加しよう
・Mainメソッドにおいて、コンストラクタ④を呼ぶ処理と、結果を表示する処理を追加しよう

作成例

//アレンジ演習:p.169 construct02.cs
using System;
class MyClass {
    private string name;    //名前:外部から見えないインスタンス変数
    private int age;        //年齢:外部から見えないインスタンス変数
    private string address; //住所:外部から見えないインスタンス変数
    public void Show() { //戻り値のないインスタンスメソッド
        string toshi; //メソッド内で用いるローカル変数
        if (age == -1) { //年齢が-1になっていたら
            toshi = "不明";
        } else { 
            toshi = age.ToString(); //int型から文字列化して代入
        }
        Console.WriteLine("氏名:{0} 住所:{1} 年齢:{2}", name, address, toshi); 
    }
    public MyClass(string str) { //引数のあるコンストラクタ①(文字列:名前)
        name = str; 
        address = "不定"; //住所は規定値
        age = -1; //年齢は規定値
    }
    public MyClass(int x) { //引数のあるコンストラクタ②(整数:年齢)
        age = x; 
        name = "不明"; //名前は規定値
        address = "不定"; //住所は規定値
    }
    public MyClass(string str1, string str2, int x) { //引数のあるコンストラクタ③(文字列:名前,文字列:住所,整数:年齢)
        name = str1; 
        address = str2; 
        age = x; 
    }
    public MyClass(string str1, int x) { //【以下追加】引数のあるコンストラクタ④(文字列:名前,整数:年齢)
        name = str1; 
        age = x; 
        address = "不定"; //住所は規定値
    }
}
class construct01 {
    public static void Main() {
        MyClass mc1 = new MyClass(18); //コンストラクタ②が呼ばれる
        MyClass mc2 = new MyClass("粂井康孝"); //コンストラクタ①が呼ばれる
        MyClass mc3 = new MyClass("田中太郎", "東京都", 32); //コンストラクタ③が呼ばれる
        MyClass mc4 = new MyClass("田中太郎", 32); //【追加】コンストラクタ④が呼ばれる
        mc1.Show(); 
        mc2.Show(); 
        mc3.Show(); 
        mc4.Show(); //【追加】 
    }
}

p.171(コンストラクタのオーバーロードとデフォルトコンストラクタ)

・p.167の通り、コンストラクタを一切記述しないと、引数無し中身無しのコンストラクタが内部的に用意されて用いられる
・これに対して、p.169 construct02.csのように、引数有りのコンストラクタを記述できるが、こうすると、
 引数無し中身無しのコンストラクタは用意されなくなる
・よって、必要があれば、自前で、引数無し中身無しのコンストラクタを記述して、オーバーロードにすること

アレンジ演習:p.169 construct02.cs

・名前を"不明"、住所を"不定"、年齢を-1にする、引数で受け取らないコンストラクタ⑤を追加しよう
・Mainメソッドにおいて、コンストラクタ⑤を呼ぶ処理と、結果を表示する処理を追加しよう

作成例

//アレンジ演習:p.169 construct02.cs
using System;
class MyClass {
    private string name;    //名前:外部から見えないインスタンス変数
    private int age;        //年齢:外部から見えないインスタンス変数
    private string address; //住所:外部から見えないインスタンス変数
    public void Show() { //戻り値のないインスタンスメソッド
        string toshi; //メソッド内で用いるローカル変数
        if (age == -1) { //年齢が-1になっていたら
            toshi = "不明";
        } else { 
            toshi = age.ToString(); //int型から文字列化して代入
        }
        Console.WriteLine("氏名:{0} 住所:{1} 年齢:{2}", name, address, toshi); 
    }
    public MyClass(string str) { //引数のあるコンストラクタ①(文字列:名前)
        name = str; 
        address = "不定"; //住所は規定値
        age = -1; //年齢は規定値
    }
    public MyClass(int x) { //引数のあるコンストラクタ②(整数:年齢)
        age = x; 
        name = "不明"; //名前は規定値
        address = "不定"; //住所は規定値
    }
    public MyClass(string str1, string str2, int x) { //引数のあるコンストラクタ③(文字列:名前,文字列:住所,整数:年齢)
        name = str1; 
        address = str2; 
        age = x; 
    }
    public MyClass(string str1, int x) { //引数のあるコンストラクタ④(文字列:名前,整数:年齢)
        name = str1; 
        age = x; 
        address = "不定"; //住所は規定値
    }
    public MyClass() { //【以下追加】引数の無いコンストラクタ⑤
        name = "不明"; //名前は規定値
        age = -1; //年齢は規定値
        address = "不定"; //住所は規定値
    }
}
class construct01 {
    public static void Main() {
        MyClass mc1 = new MyClass(18); //コンストラクタ②が呼ばれる
        MyClass mc2 = new MyClass("粂井康孝"); //コンストラクタ①が呼ばれる
        MyClass mc3 = new MyClass("田中太郎", "東京都", 32); //コンストラクタ③が呼ばれる
        MyClass mc4 = new MyClass("田中太郎", 32); //コンストラクタ④が呼ばれる
        MyClass mc5 = new MyClass(); //【追加】コンストラクタ⑤が呼ばれる
        mc1.Show(); 
        mc2.Show(); 
        mc3.Show(); 
        mc4.Show();
        mc5.Show(); //【追加】 
    }
}

p.171 デストラクタ

・プログラムの終了や有効期間の終了によてオブジェクトが破棄される時、その直前に自動的に呼び出されるのがデストラクタ
・よって、コンストラクタに似ているが、仕様の違いに注意
・主に、利用していたリソース(資源=ファイルやデータベース、通信など)の解放のような「後始末」に向く。
・デストラクタはメソッドに似ているが、アクセス修飾子や引数、戻り値はない。
・引数がないのでオーナーライドもできない
・デストラクタは名前もなく「~クラス名」固定とする。
・書式: ~クラス名() { 内容 }
・コンストラクタと同様で、記述がなければ自動的に中身の無いデストラクタが内部的に用意されて用いられる
・デストラクタはインスタンスに含まれるので、複数のインスタンスを生成すると、複数のデストラクタが動作する
・この時の実行順序は決まっていない

p.172 destruct01.cs

//p.172 destruct01.cs
using System;
class DestructTest {
    int x;
    // デストラクタ
    ~DestructTest() {
        Console.WriteLine("デストラクタが呼ばれました");
        Console.WriteLine("xは{0}です", x);
    }
    // 引数付きコンストラクタ
    public DestructTest(int n) {
        Console.WriteLine("コンストラクタが呼ばれました");
        x = n; 
        Console.WriteLine("xに{0}を代入しました", n);
    }
}
class destruct {
    public static void Main(){
        DestructTest dt1 = new DestructTest(1);
        Console.WriteLine("dt1生成");
        DestructTest dt2 = new DestructTest(2);
        Console.WriteLine("dt2生成");
        DestructTest dt3 = new DestructTest(3);
        Console.WriteLine("dt3生成"); //この直後に3つのデストラクタが順不同で実行される
    }
}

アレンジ演習:p.172 destruct01.cs

・オブジェクトが参照変数からアクセスできなくなると、消去の対象となり、消去時にデストラクタが動作する
・しかし、メモリや処理の余裕がある間は、この作業(ガベージコレクション)は実行されない
・このことを試すために、DestructTest型の参照変数dt1を再利用してみよう
        DestructTest dt1 = new DestructTest(1); //オブジェクト①生成
        dt1 = new DestructTest(2); //オブジェクト②生成、ここで①が消去対象になる
        dt1 = new DestructTest(3); //オブジェクト③生成、ここで②も消去対象になる

作成例

//アレンジ演習:p.172 destruct01.cs
using System;
class DestructTest {
    int x;
    // デストラクタ
    ~DestructTest() {
        Console.WriteLine("デストラクタが呼ばれました");
        Console.WriteLine("xは{0}です", x);
    }
    // 引数付きコンストラクタ
    public DestructTest(int n) {
        Console.WriteLine("コンストラクタが呼ばれました");
        x = n; 
        Console.WriteLine("xに{0}を代入しました", n);
    }
}
class destruct {
    public static void Main(){
        DestructTest dt1 = new DestructTest(1); //オブジェクト①生成
        dt1 = new DestructTest(2); //オブジェクト②生成、ここで①が消去対象になる
        dt1 = new DestructTest(3); //オブジェクト③生成、ここで②も消去対象になる
    } //実際は①②もプログラム終了まで残ってしまい、まとめてデストラクタが動作する
}

p.174 this

・メソッドやコンストラクタの中で、自分が所属するオブジェクトへの参照を得たい場合に用いる
・よって、p.174上の例のように、インスタンス変数であることを「this.」を前置して明示することもできるが、通常は省略する
【補足①】
・thisの用途として、コンストラクタの引数名をデータメンバ名と同じにする手法が良く用いられる
・これで、インスタンス変数に「this.」を前置して「this.メンバ名 = メンバ名;」と表記できる
 例: 
 class Slime { 
  int hp, mp; 
  public Slime(hp, mp) { this.hp = hp; this.mp = mp; } //コンストラクタの引数がメンバ名と同じ
 }
【補足②】
・thisの用途として、コンストラクタのオーバロードにおいて、他のコンストラクタをthisで呼ぶ手法が良く用いられる
・書式: public クラス名(引数リスト) : this(引数リスト) {}
・この書式をコンストラクタ初期化子という
・これで、複数のコンストラクタにまたがって同一内容を記述することを避けられる
 例: 
 class Slime { 
  int hp, mp; 
  public Slime(int hp, int mp) { this.hp = hp; this.mp = mp; } //HPとMPを指定するコンストラクタ①
  public Slime(int hp) : this(hp, 0) {} //HPだけを指定するコンストラクタ②は①を利用
  public Slime() : this(0, 0) {} //引数を指定しないコンストラクタ③も①を利用
 }

アレンジ演習:p.169 construct02.cs ⇒ p.169 construct02a.cs

・【補足①】を用いて、3つのコンストラクタの引数名をメンバ名と同じにしよう

作成例

//アレンジ演習:p.169 construct02.cs
using System;
class MyClass {
    private string name;    //名前:外部から見えないインスタンス変数
    private int age;        //年齢:外部から見えないインスタンス変数
    private string address; //住所:外部から見えないインスタンス変数
    public void Show() { //戻り値のないインスタンスメソッド
        string toshi; //メソッド内で用いるローカル変数
        if (age == -1) { //年齢が-1になっていたら
            toshi = "不明";
        } else { 
            toshi = age.ToString(); //int型から文字列化して代入
        }
        Console.WriteLine("氏名:{0} 住所:{1} 年齢:{2}", name, address, toshi); 
    }
    public MyClass(string name) { //【変更】引数のあるコンストラクタ①(文字列:名前)
        this.name = name; //【変更】
        address = "不定"; //住所は規定値
        age = -1; //年齢は規定値
    }
    public MyClass(int age) { //【変更】引数のあるコンストラクタ②(整数:年齢)
        this.age = age; //【変更】
        name = "不明"; //名前は規定値
        address = "不定"; //住所は規定値
    }
    public MyClass(string name, string address, int age) { //【変更】引数のあるコンストラクタ③(文字列:名前,文字列:住所,整数:年齢)
        this.name = name; //【変更】
        this.address = address; //【変更】
        this.age = age; //【変更】
    }
}
class construct01 {
    public static void Main() {
        MyClass mc1 = new MyClass(18); //コンストラクタ②が呼ばれる
        MyClass mc2 = new MyClass("粂井康孝"); //コンストラクタ①が呼ばれる
        MyClass mc3 = new MyClass("田中太郎", "東京都", 32); //コンストラクタ③が呼ばれる
        mc1.Show(); 
        mc2.Show(); 
        mc3.Show(); 
    }
}

アレンジ演習:p.169 construct02a.cs

・さらに【補足②】を用いて、コンストラクタ①と②はコンストラクタ③を用いるようにしよう

作成例

//アレンジ演習:p.169 construct02.cs
using System;
class MyClass {
    private string name;    //名前:外部から見えないインスタンス変数
    private int age;        //年齢:外部から見えないインスタンス変数
    private string address; //住所:外部から見えないインスタンス変数
    public void Show() { //戻り値のないインスタンスメソッド
        string toshi; //メソッド内で用いるローカル変数
        if (age == -1) { //年齢が-1になっていたら
            toshi = "不明";
        } else { 
            toshi = age.ToString(); //int型から文字列化して代入
        }
        Console.WriteLine("氏名:{0} 住所:{1} 年齢:{2}", name, address, toshi); 
    }
    public MyClass(string name) : this(name, "不定", -1) { } //【変更】コンストラクタ①(文字列:名前)⇒③を呼ぶ
    public MyClass(int age) : this("不明", "不定", age) { }  //【変更】コンストラクタ②(整数:年齢)⇒③を呼ぶ
    public MyClass(string name, string address, int age) { //引数のあるコンストラクタ③(文字列:名前,文字列:住所,整数:年齢)
        this.name = name; 
        this.address = address; 
        this.age = age;
    }
}
class construct01 {
    public static void Main() {
        MyClass mc1 = new MyClass(18); //コンストラクタ②が呼ばれる
        MyClass mc2 = new MyClass("粂井康孝"); //コンストラクタ①が呼ばれる
        MyClass mc3 = new MyClass("田中太郎", "東京都", 32); //コンストラクタ③が呼ばれる
        mc1.Show(); 
        mc2.Show(); 
        mc3.Show(); 
    }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です