今週の話題

販売本数ランキング 今回トップは「Marvel’s Spider-Man 2(PS5)」GO!
業績回復鮮明のシリコンスタジオ、ゲームエンジンの需要高まる自動車業界でも存在感を発揮【ゲーム企業の決算を読む】GO!
Apple、「GeForce NOW」などゲームストリーミングサービスの制限緩和―単一アプリでフル機能が提供可能に GO!
ブロックチェーンゲーム『キャプテン翼 -RIVALS-』、スマホアプリ版のサービス開始 事前登録は10万人突破 GO!
『FF16』が日本PS5部門でトップに!2023年のPS Store年間ダウンロードランキング公開 GO!
3DS/Wii Uのオンラインプレイサービスが2024年4月9日に終了へ GO!

『パルワールド』の“ポケモン”Modがコミュニティで波紋呼ぶ―動画等は任天堂により権利者削除、モデルの出処も怪しい GO!
ポケモン社が類似の他社ゲームに対して「いかなる利用も許諾しておりません」とコメントを発表。『パルワールド』を示唆か。知的財産権の侵害については「調査を行った上で、適切な対応を取っていく所存」GO!
マイクロソフト約1,900人解雇―アクティビジョン買収でゲーム部門全体の約8%にあたる人員整理 GO!
開発期間は6年以上…Blizzardレイオフで開発中止の未発表サバイバルゲームは社内で好評だった模様 GO!
リリースからたった4ヶ月での終了告知…ネクソンの無料大規模対戦アクション『Warhaven』4月にサービス終了へ GO!

講義メモ:後半

p.176 既存のクラスを使ってみる

・ここまでで、System、Mathなどの既存のクラスを利用しているが、ここでは、インスタンスメソッドを持つクラスの一例として、
 ArrayListクラスを用いよう
・ArrayListクラスは、配列の機能を拡張した仕組みを提供するもので、配列にはない柔軟な利用が可能
・利用には「using Sytem.Collections;」を指定する
 ※ ArrayListクラスなどのデータ構造を表すことのできるクラスをコレクションと呼ぶ
・インスタンスを生成すると、配列に似たデータ構造が生成されるが、配列とは異なり、要素数を事前に決める必要がなく、
 動的に変更することもできる
・要素の追加にはインスタンスメソッドのAdd(データ)を用い、追加にしたがって要素数が拡張される
・件数を返すCountプロパティも利用可能
 ※ プロパティは特殊なメソッドで8章で説明
・格納済の要素は、配列と同様にオブジェクト名[添字]で直接アクセスできる

p.177 arraylist01.cs

//p.177 arraylist01.cs
using System;
using System.Collections; //ArrayList用
class arraylist01 {
    public static void Main() {
        bool bEnd = false; //終了フラグをオフで初期化
        string strData; //読込用
        double sum = 0.0; //合計
        ArrayList al = new ArrayList(); //ArrayListオブジェクトを生成
        while (true) { //無限ループ
            Console.Write("データ(数値以外入力で終了)-- ");
            strData = Console.ReadLine();
            if (!Char.IsDigit(strData[0]) && strData[0] != '-') { //1文字目が数字ではなくマイナスでもない?
                bEnd = true; //終了フラグをオンにする
            } else { //数字またはマイナスなら
                al.Add(double.Parse(strData)); //実数に変換してArrayListに格納
            }
            if (bEnd) { //終了フラグがオン?
                break; //繰返しを抜ける
            }
        }
        for (int i = 0; i < al.Count; i++) { //ArrayListに格納した件数の分、繰返す
            Console.WriteLine("Data[{0}] = {1}", i + 1, al[i]); //値を表示
            sum += (double)al[i]; //合計に足し込む
        }
        int count = al.Count; //ArrayListに格納した件数を得る
        double avr = sum / count; //合計を件数で割って平均値を得る
        Console.WriteLine("データ個数 = {0}", count);
        Console.WriteLine("平均値 = {0}", avr);
    }
}

アレンジ演習:p.177 arraylist01.cs

・Countプロパティを2回呼び出しているが、1回にしよう
・終了フラグを廃止しよう

作成例

//アレンジ演習:p.177 arraylist01.cs
using System;
using System.Collections; //ArrayList用
class arraylist01 {
    public static void Main() {
        string strData; //読込用
        double sum = 0.0; //合計
        ArrayList al = new ArrayList(); //ArrayListオブジェクトを生成
        while (true) { //無限ループ
            Console.Write("データ(数値以外入力で終了)-- ");
            strData = Console.ReadLine();
            if (!Char.IsDigit(strData[0]) && strData[0] != '-') { //1文字目が数字ではなくマイナスでもない?
                break; //【移動】繰返しを抜ける
            } else { //数字またはマイナスなら
                al.Add(double.Parse(strData)); //実数に変換してArrayListに格納
            }
        }
        int count = al.Count; //【移動】ArrayListに格納した件数を得る
        for (int i = 0; i < count; i++) { //【変更】件数の分、繰返す
            Console.WriteLine("Data[{0}] = {1}", i + 1, al[i]); //値を表示
            sum += (double)al[i]; //合計に足し込む
        }
        Console.WriteLine("データ個数 = {0}", count);
        Console.WriteLine("平均値 = {0}", sum / count); //【変更】合計を件数で割って平均値を得る
    }
}

p.180 練習問題1 ヒント

・クラス名や変数名は自由
・例: class MyClass { public int i; }
・読みだした値は確認用に表示すると良い

作成例

//p.180 練習問題1
using System;
class MyClass { public int i; } //int型のpublicインスタンス変数のみを持つクラス
class ex0701 {
    public static void Main() {
        MyClass mc = new MyClass(); //MyClassオブジェクトを生成
        mc.i = 10;
        Console.WriteLine("mc.i = {0}", mc.i);
    }
}

p.180 練習問題2 ヒント

・クラス名やメソッド名は自由
・ただし、オーバーロードなので、同じメソッド名とすること
・Mainメソッドから呼び出すために、2つのメソッドはpublicにする
・int型とint型の和を求めるメソッドは戻り値型もintにする
・double型とdouble型の和を求めるメソッドは戻り値型もdoubleにする
・結果は確認用に表示すると良い

作成例

//p.180 練習問題2
using System;
class MyClass {
    public int sum(int a, int b) { //メソッド①
        return a + b;
    }
    public double sum(double a, double b) { //メソッド②=①のオーバーロード
        return a + b;
    }
}
class ex0702 {
    public static void Main() {
        MyClass mc = new MyClass(); //MyClassオブジェクトを生成
        Console.WriteLine("整数 {0} + {1} = {2}", 2, 3, mc.sum(2, 3)); //メソッド①が呼ばれる
        Console.WriteLine("実数 {0} + {1} = {2}", 3.14, 4.99, mc.sum(3.14, 4.99)); //メソッド②が呼ばれる
    }
}

第8章 クラスとメソッドの詳細

p.181 メソッドの再帰呼び出し

・最近のプログラム言語では、あるメソッドの中で自分自身を呼び出すことが可能で、これを再帰という。
・再帰を上手く利用すると、プログラムをシンプルに記述出来る場合がある
・単純に自分自身を呼び出すと呼び出しが無限ループするので(これ以上)自分を呼び出さずに式や値を返す処置が必要

p.181 階乗を計算する

・階乗とは、ある正の整数において、その数から1までの全整数の積
 ※ 実質的にはその数から2までの全整数の積になる
・整数nの階乗を「n!」で表し、例えば、2!は2、3!は6、4!は24、5!は120、…
・これを逆順で展開すると
 5! = 5×4×3×2×1
 4! =    4×3×2×1
 3! =       3×2×1
・なので、5!=5×4!、4!=4×3! であることから「n! = n×(n-1)!」が導ける。
・これをメソッドFactにすると、
 int CalcFact(int n) { //nの階乗
  return n * CalcFact(n - 1); //n×(n-1)!を返す(再帰する)
 }
・これに、再帰の終了条件として「0の階乗は1」を加えると良い
 int CalcFact(int n) { //nの階乗
  return (n > 0) ? n * CalcFact(n - 1) : 1; //nが0超ならn×(n-1)!を返す(再帰する)でなければ1を返す
 }
・p.182 fact01.csは上記を展開したメソッドになっている

p.182 fact01.cs

//p.182 fact01.cs
using System;
class Fact {
    public long CalcFact(int n) { //n!を返す
        long fact; //階乗値
        if (n == 0) { //0!は1なので(再帰の終了条件になる)
            fact = 1; //1を返す
        } else { //1以上ならば
            fact = n * CalcFact(n - 1); //「n! = n * (n - 1)!」により再帰する
        }
        return fact; //階乗値を返す
    }
}
class fact01 {
    public static void Main() {
        Fact f = new Fact();
        for (int i = 0; i <= 20; i++) {
            Console.WriteLine("{0}! = {1}", i, f.CalcFact(i));
        }
    }
}

アレンジ演習:p.182 fact01.cs

・CalcFact(int n)メソッドを上記を用いてシンプルにしよう

提出:アレンジ演習:p.182 fact01.cs

講義メモ

・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(); 
    }
}

今週の話題

販売本数ランキング 今回トップは「スーパーマリオブラザーズ ワンダー(Switch)」GO!
『フォートナイト』でプログラミングやデジタル技術を習得―茨城県で「FORTNITE UEFN クリエイティブ講座」開催 GO!
第24回「GDC Awards」ノミネート作品発表!『バルダーズ・ゲート3』と『ゼルダの伝説 ティアキン』が最多7部門で選出 GO!
ユービーアイソフト、サブスクは「今後大きな成長が見込める」と自信―PC向けサブスクプランをリブランディング GO!
「理想を追い求めたゲームが存在する余地が無くなる」…『バルダーズ・ゲート3』開発者がゲームのサブスクリプションに否定的な見解示す GO!
吉田直樹氏が『FF17』に対する胸の内を語る―「同じおじさんがやっていくよりは、若い世代にチャレンジしてほしい」GO!
『プロセカ』クリエイターがLive2D制作フローや演出のノウハウを惜しみなく紹介―Colorful Palette講演レポート【alive 2023】GO!

『LOST ARK』サービス終了告知―満足できるサービスの提供が困難であると判断 GO!
『GTA5』マイケル役俳優が自身の声を無許可使用したAIチャットボットに猛反発 GO!

講義メモ 後半

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

講義メモ

・p.159(Mainメソッドを含むクラス)から

p.159 Mainメソッドを含むクラス

・simpleclass03などのように、インスタンス変数を持つクラスと、Mainメソッドを持つクラスは別にするのが基本
・そして、インスタンス変数を持つクラスはプログラム部品として設計・活用することが多い
・しかし、Mainメソッドを持つクラスにインスタンス変数を持つこともできる
・このようなクラスのインスタンスにはMainメソッドは含まれないので、Mainメソッドを持つクラスを別にした場合と
 同様に動作する
・よって、例外的な記述法だが、次項以降で説明するメソッドのテスト処理の記述などに用いることもある

p.159 simpleclass04

//p.159 simpleclass04
using System;
class simpleclass04 {
    private int x; //インスタンス変数(このクラス内からのみ利用可能)
    public static void Main() {
        simpleclass04 s; //自分が属するクラスを型とする変数を定義できる
        s = new simpleclass04(); //自分が属するクラスのインスタンスを生成できる
        s.x = 10; //このインスタンスの中に、インスタンス変数があるので代入可能
        Console.WriteLine("s.x = " + s.x); //表示も可能
    }
}

p.160 メソッドを定義しよう

・C言語の構造体とは異なり、クラスには処理を行うメソッドを自由に定義できる
・なお、Mainメソッドは特別な意味をもつメソッドとして扱われる
・メソッドはC言語などの関数と同じ仕掛けで、0個以上の情報を受け取り、処理して、0または1個の情報を返すことができる
・返す値を戻り値(返却値)といい、メソッド定義の冒頭で、その型を示す。
・なお、返す値が0個の場合は、無を意味するvoidを指定する
・返す値が1個の場合は、メソッドの中に「return 式または値;」を記述し、どういうアルゴリズムになっていても、
 必ずreturnができないとコンパイルエラーになるので注意。
・なお、returnの後続部分は実行されないので、絶対に実行されない状態にしてしまうと、コンパイルエラーになる
・returnには式や他のメソッドの呼び出しが記述できる(メソッドの処理内容を全て記述できることもある)
・例: int add3(int a, int b, int c) { return a + b + c; }
・0個以上の情報を受け取る仕掛けが引数で、上のa,b,cのように、型と共に引数リスト(パラメータリスト)として、
 メソッド名直後のカッコ内に記述する
・0個の場合も、カッコは省略不可
※ メソッド側で定義している引数を仮引数ともいう(メソッドを呼び出す側で指定するのは実引数)
・メソッドのアクセス修飾子は、通常、private(利用自由)かpublic(外部からの利用不可)
・定義書式: アクセス修飾子 戻り値型 メソッド名(引数リスト) {…}

・例:
 public int add3(int a, int b, int c) { //利用自由でint型3引数をを受け取りint型の値を返すメソッド
  return a + b + c; //3引数の値の和を返す
 }

p.161(メソッドの呼び出し)

・インスタンス変数と同様に、インスタンスを生成すると呼び出し可能になるのが基本
・インスタンス変数と同様に「インスタンス名.メソッド名(引数リスト)」と呼び出すことが可能
・戻り値がvoidではない場合、戻り値を受け取って変数に格納したり、そのまま表示したりすることが可能
・例:
class Sub {
 public int add3(int a, int b, int c) { //利用自由でint型3引数をを受け取りint型の値を返すメソッド
  return a + b + c; //3引数の値の和を返す
 }
}
class Center {
 :
 Sub s = new Sub();
 int sum = s.add3(1,2,3); //add3メソッドの戻り値を変数の初期化に用いることもOK

・通常のメソッドはインスタンス変数と同様に、インスタンス経由でアクセスされるので、インスタンスメソッドともいう
・メソッドに定義されている引数の数と型が呼び出しにおいてチェックされ、異なるとエラーになる
・なお、型が異なっても暗黙の変換が可能な場合はエラーにならない
・実引数と仮引数は名前は異なって良く、メソッドの汎用性を考えると異なる名前の方が良い
・実引数と仮引数は定義順に割り当てられる
・実引数の代わりに、値を直接記述しても良い

p.161 method01.cs

//p.161 method01.cs
using System;
class MyClass { //メソッドを持つクラス
    public int Add(int x, int y) { //外部利用可能で戻り値型がintで引数がint型2値のAddメソッドの定義
        int z; //メソッド内部で定義されているのでローカル変数
        z = x + y;
        return z; //整数の和が格納された変数を指定することで、その値が返される
    }
}
class method01 {
    public static void Main() {
        MyClass a = new MyClass(); //メソッドを持つクラスのインスタンスを生成
        int sum; //合計用
        sum = a.Add(100, 200); //インスタンス経由でメソッドを呼び、整数2値を渡し、戻り値を変数に代入
        Console.WriteLine("sum = {0}", sum);
    }
}

アレンジ演習:p.161 method01.cs

・メソッドに渡す整数2値を(100, 200固定ではなく)コンソールから入力できるようにしよう

作成例

//アレンジ演習:p.161 method01.cs
using System;
class MyClass { //メソッドを持つクラス
    public int Add(int x, int y) { //外部利用可能で戻り値型がintで引数がint型2値のAddメソッドの定義
        int z; //メソッド内部で定義されているのでローカル変数
        z = x + y;
        return z; //整数の和が格納された変数を指定することで、その値が返される
    }
}
class method01 {
    public static void Main() {
        MyClass a = new MyClass(); //メソッドを持つクラスのインスタンスを生成
        int sum; //合計用
        Console.Write("x:"); int x = int.Parse(Console.ReadLine()); //【追加】コンソールから入力
        Console.Write("y:"); int y = int.Parse(Console.ReadLine()); //【追加】コンソールから入力
        sum = a.Add(x, y); //【変更】インスタンス経由でメソッドを呼び、整数2値を渡し、戻り値を変数に代入
        Console.WriteLine("sum = {0}", sum);
    }
}

p.163 bmiclass.cs

//p.163 bmiclass.cs
using System;
class BMI { //BMI計算用の部品クラス
    private double blm; //身長(m単位):外部から見えないインスタンスう変数
    public double Calc(double bl, double bw) { //利用自由なインスタンスメソッド(戻り値有、引数2値)
        blm = bl / 100.0; //引数blで受け取った身長(cm単位)をメートル単位に換算
        return bw / Math.Pow(blm, 2.0); //BMIを計算して(体重÷身長の2乗)返す
    }
}
class bmiclass {
    public static void Main() {
        string strBl, strBw; //入力用
        double blcm, bwkg; //変換結果
        Console.Write("身長(cm)---");
        strBl = Console.ReadLine();
        blcm = Double.Parse(strBl);
        Console.Write("体重(kg)---");
        strBw = Console.ReadLine();
        bwkg = Double.Parse(strBw);
        BMI bmi = new BMI(); //Calcメソッドを持つBMIクラスのインスタンスを生成
        Console.WriteLine("BMIは{0:#.##}です", bmi.Calc(blcm, bwkg)); //メソッドを呼んで戻り値を表示
    }
}

p.164(値を返さないメソッド)

・値を返さないメソッドでは、戻り値型をvoidとする(省略不可)
・値を返さないメソッドには、returnは記述不要(記述しても良い)
・なお、メソッドを途中にreturnを記述して、途中で打ち切ることも可能だが、実行されることがない文ができてしまうとエラーになる
・OKな例:
 void foo(int a) {
  if (a == 0) { return; } //0の時はここで打ち切ってOK
  : //これ以降は0以外の時に実行されるのでOK
 }
・NGな例:
 void foo(int a) {
  :
  return; //どんな場合もここで打ち切ってOK
  : //これ以降は実行されないのでNG
 }
・なお、p.165 noreturn.csのすべてのreturnは省略可能だが、記述しても良い
・値を返さないメソッドのメソッド末尾のreturnは省略することが多い
・メソッド途中のreturnは省略可能な場合でも省略しないことがある(保守性が上がる)

p.165 noreturnvalue.cs

//p.165 noreturnvalue.cs
using System;
class Kakeibo {
    private int total = 0; //残高:外部から見えないインスタンス変数
    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.166(カプセル化)

・インスタンス変数のうち、外部から直接アクセスする必要がないものや、させない方が良いものはprivate指定すると良い
・外部から直接アクセスさせないようにprivate指定して変数値が適切な状態に保つことをカプセル化という
・例えば、身長や体重を正の数に制限したり、点数を0から100までに制限する場合などに用いる
・この場合、必要に応じてprivate指定のインスタンス変数にアクセスするメソッドを記述し、この中で、アクセス内容を制限する
例:
 private double bw; //体重:外部から見えないインスタンス変数
 public void setBw(double w) { if (w > 0) {bw = w;} } //引数で体重を受け取って正の数なら代入
 public double getBw() { return bw;} //体重を返す
※ このようなメソッドをアクセッサといい、代入用をセッター、参照用をゲッターともいう
※ なお、C#には、アクセッサの実装に便利なプロパティ(p.207)という仕掛けがあり、プロパティを用いるのが基本