講義メモ 後半

p.167 コンストラクタ

・new等でインスタンスの生成を行う時に、同時に実行したい処理を特殊な書式で記述することができる
・これがコンストラクタで、省略すると、自動的に中身がないコンストラクタが用意されて用いられる
・コンストラクタ=構築なので、生成時に呼ばれる特殊なメソッドを指す
・コンストラクタを自前で記述することで、インスタンスの生成を行う時に実行したいことを書ける
・主に、データメンバの初期化や、開始処理などの記述に用いて「必ず実行させる」ことが可能
・なお、コンストラクタには名前はなく、クラス名で記述し、public指定で、戻り値はない
・主な書式: public クラス名() {…}
・「new クラス名()」で呼び出して欲しい場合はカッコ内は空にする
 ※ 引数を指定することも可能で、引数のない定義と両立できる(後述:オーバーロード)

p.167 construct01.cs

//p.167 construct01.cs
using System;
class MyClass {
    int x; //外部から見えないインスタンス変数
    public void showx() { //表示:インスタンスメソッド
        Console.WriteLine("x = " + x);
    }
    public MyClass() { //コンストラクタ
        x = 10; //インスタンス変数の初期化
        Console.WriteLine("xに10を代入しました");
    }
}
class construct01 {
    public static void Main() {
        MyClass mc = new MyClass(); //インスタンスの生成と共にコンストラクタを実行
        mc.showx(); //インスタンスメソッドを実行
    }
}

アレンジ演習:p.165 noreturnvalue.cs

・残高を0で初期化する処理をコンストラクタで行うようにしよう
・実行結果は変わらないので、テスト用にコンストラクタに「初期化しました」と表示する処理を加えよう

作成例

//アレンジ演習:p.165 noreturnvalue.cs
using System;
class Kakeibo {
    private int total; //【変更】残高:外部から見えないインスタンス変数
    public Kakeibo() { //【以下追加】コンストラクタ
        total = 0; //インスタンス変数を初期化
        Console.WriteLine("初期化しました"); //テスト用
    }
    public void nyukin(int en) { //入金:戻り値のないインスタンスメソッド
        total += en;
        Console.WriteLine("{0}円を入金しました", en);
        // return; //この後はないので省略可能
    }
    public void shishutsu(int en) { //支出:戻り値のないインスタンスメソッド
        if (total < en) { //残高不足?
            Console.WriteLine("{0}円も支出できません", en);
            // return; //この後にelseしかないので省略可能
        } else {
            total -= en;
            Console.WriteLine("{0}円を支出しました", en);
            // return; //この後はelseの終わりしかないので省略可能
        }
    }
    public void gettotal() { //残高照会:戻り値のないインスタンスメソッド
        if (total == 0) {
            Console.WriteLine("残高はありません");
            // return; //この後にelseしかないので省略可能
        } else {
            Console.WriteLine("残高は{0}円です", total);
            // return; //この後はelseの終わりしかないので省略可能
        }
    }
}
class noreturnvalue {
    public static void Main() {
        Kakeibo k = new Kakeibo();
        k.gettotal(); //残高照会⇒残高はありません
        k.nyukin(1000); //入金1000円
        k.gettotal(); //残高照会⇒1000円です
        k.nyukin(2000); //入金2000円
        k.gettotal(); //残高照会⇒3000円です
        k.shishutsu(500); //支出500円
        k.gettotal(); //残高照会⇒2500円です
        k.shishutsu(10000); //支出10000円⇒支出できません
        k.gettotal(); //残高照会⇒2500円です
    }
}

p.168(引数のあるコンストラクタ)

・コンストラクタに引数リストを記述することができる
・これにより、インスタンス変数の初期値を引数で渡すことが多い
・例:
 public Kakeibo(int t) { //引数のあるコンストラクタ
  total = t; //インスタンス変数を引数の値で初期化
 }
・引数のあるコンストラクタを呼び出すには、newのカッコ内に引数の値や式を記述する
・例:
 Kakeibo k = new Kakeibo(10000); //インスタンスを生成し、残高を10000円とする

アレンジ演習:p.165 noreturnvalue.cs

・残高を引数tで初期化する処理をコンストラクタで行うようにしよう
・上記の例の通り、インスタンスを生成し、残高を10000円としよう

作成例

//アレンジ演習:p.165 noreturnvalue.cs
using System;
class Kakeibo {
    private int total; //残高:外部から見えないインスタンス変数
    public Kakeibo(int t) { //【変更】コンストラクタ
        total = t; //【変更】インスタンス変数を引数で初期化
        Console.WriteLine("初期化しました"); //テスト用
    }
    public void nyukin(int en) { //入金:戻り値のないインスタンスメソッド
        total += en;
        Console.WriteLine("{0}円を入金しました", en);
        // return; //この後はないので省略可能
    }
    public void shishutsu(int en) { //支出:戻り値のないインスタンスメソッド
        if (total < en) { //残高不足?
            Console.WriteLine("{0}円も支出できません", en);
            // return; //この後にelseしかないので省略可能
        } else {
            total -= en;
            Console.WriteLine("{0}円を支出しました", en);
            // return; //この後はelseの終わりしかないので省略可能
        }
    }
    public void gettotal() { //残高照会:戻り値のないインスタンスメソッド
        if (total == 0) {
            Console.WriteLine("残高はありません");
            // return; //この後にelseしかないので省略可能
        } else {
            Console.WriteLine("残高は{0}円です", total);
            // return; //この後はelseの終わりしかないので省略可能
        }
    }
}
class noreturnvalue {
    public static void Main() {
        Kakeibo k = new Kakeibo(10000); //【変更】引数で残高の初期値を与える
        k.gettotal(); //残高照会
        k.nyukin(1000); //入金
        k.gettotal(); //残高照会
        k.nyukin(2000); //入金
        k.gettotal(); //残高照会
        k.shishutsu(500); //支出
        k.gettotal(); //残高照会
        k.shishutsu(10000); //支出
        k.gettotal(); //残高照会
    }
}

p.168(コンストラクタのオーバーロード)

・引数のないコンストラクタと、引数のあるコンストラクタを併記できる
・newにおいて引数が指定されたかどうかによって、自動的に使い分けが行われる
・また、この時に、引数とコンストラクタの引数リストのチェックが行われ、引数の個数と型が一致しないとエラーになる
・このチェックがあるので、引数のあるコンストラクタを複数併記でき、呼び出しを一致するものが利用される
・この仕掛けをオーバーロード(多重定義)という
・また、チェックに用いる「引数の個数と型の並び」をシグニチャという
・定義例:
 public Kakeibo() { //引数の無いコンストラクタ
  total = 0; //インスタンス変数を0で初期化
 }
 public Kakeibo(int t) { //int型引数1個のあるコンストラクタ①
  total = t; //インスタンス変数を引数の値で初期化
 }
 public Kakeibo(int t, int u) { //int型引数2個のあるコンストラクタ②
  total = t; //インスタンス変数を引数の値で初期化
  count = u; //同上
 }
・呼び出し例
 Kakeibo n = new Kakeibo(); //インスタンスを生成し、引数の無いコンストラクタを呼ぶ
 Kakeibo k = new Kakeibo(10000); //インスタンスを生成し、コンストラクタ①を呼ぶ
 Kakeibo m = new Kakeibo(20000, 3); //インスタンスを生成し、コンストラクタ②を呼ぶ
・型の並びでも区別されるので、例えば、public Kakeibo(int t, double d)と、public Kakeibo(double d, int t)は併記可能

p.169 補足:construct02.csにおけるToString()について

・ToString()は一種のメソッドで、int.Parse()と同様に、intに対して指定でき、整数を文字列にした結果を返す
※ どちらも内部的には.NET型のSystem.Int32構造体(p.275)が持つオーバライドメソッド(p.230)

p.169 construct02.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 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; 
    }
}
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 construct02.cs

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

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

コメントを残す

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