講義メモ 続き

p.195 メソッドのオーバーロード

・既述の通り、コンストラクタと同様にメソッドもオーバーロードが可能
・なお、メソッドのシグニチャには戻り値型は含まれないので、戻り値型のみが異なるメソッドのオーバーロードは認められずエラーになる

p.195 overload01.cs

//p.195 overload01.cs
using System;
class manymethods {
    public int Method(int x) {
        Console.WriteLine("第1のバージョンが呼ばれました");
        return x + 10;
    }
    public double Method(double x) {
        Console.WriteLine("第2のバージョンが呼ばれました");
        return x * 2;
    }
    public string Method(string x) {
        Console.WriteLine("第3のバージョンが呼ばれました");
        return x += "です";
    }
    public int Method(int x, int y) {
        Console.WriteLine("第4のバージョンか呼ばれました");
        return x + y;
    }
}
class overload01 {
    public static void Main() {
        manymethods m = new manymethods();
        Console.WriteLine("その戻り値は「{0}」です", m.Method(3));      //第1のバージョンが呼ばれる
        Console.WriteLine("その戻り値は「{0}」です", m.Method(3.2));    //第2のバージョンが呼ばれる
        Console.WriteLine("その戻り値は「{0}」です", m.Method("粂井")); //第3のバージョンが呼ばれる
        Console.WriteLine("その戻り値は「{0}」です", m.Method(5, 6));   //第4のバージョンが呼ばれる
    }
}

アレンジ演習:p.195 overload01.cs

・下記のシグニチャのMaxメソッドのオーバーロードを持つクラスMaxsを作成し、動作を確認しよう
 Max(int,int) //整数2値の最大値を返す
 Max(int,int,int) //整数3値の最大値を返す
 Max(int[]) //整数配列の要素の最大値を返す

作成例

//アレンジ演習:p.195 overload01.cs
using System;
class Maxs {
    public int Max(int x, int y) { //整数2値の最大値を返す
        return (x > y) ? x : y;
    }
    public int Max(int x, int y, int z) { //整数3値の最大値を返す
        int max = (x > y) ? x : y; //2値の最大値を得てから
        return (max > z) ? max : z; //3値目比べる
    }
    public int Max(int[] a) {
        int max = a[0]; //仮に先頭要素が最大とする
        for (int i = 1; i < a.Length; i++) { //先頭の次の要素から全要素について繰り返す
            if (max < a[i]) { //最大値超ならば
                max = a[i]; //最大値更新
            }
        }
        return max; //最大値を返す
    }
}
class overload01 {
    public static void Main() {
        Maxs m = new Maxs();
        Console.WriteLine("Max(3, 2) = {0}", m.Max(3, 2)); //第1のバージョンが呼ばれる
        Console.WriteLine("Max(3, 4, 2) = {0}", m.Max(3, 4, 2)); //第2のバージョンが呼ばれる
        int[] ma = {3, 4, 8, 2};
        Console.WriteLine("Max(3, 4, 8, 2) = {0}", m.Max(ma)); //第3のバージョンが呼ばれる
    }
}

作成例・効率アップバージョン

//アレンジ演習:p.195 overload01.cs
using System;
class Maxs {
    public int Max(int x, int y) { //①整数2値の最大値を返す
        int[] w = {x, y}; //2値を配列にして
        return Max(w); //③を呼ぶ
    }
    public int Max(int x, int y, int z) { //②整数3値の最大値を返す
        int[] w = {x, y, z}; //3値を配列にして
        return Max(w); //③を呼ぶ
    }
    public int Max(int[] a) { //③整数配列の最大値を返す
        int max = a[0]; //仮に先頭要素が最大とする
        for (int i = 1; i < a.Length; i++) { //先頭の次の要素から全要素について繰り返す
            if (max < a[i]) { //最大値超ならば
                max = a[i]; //最大値更新
            }
        }
        return max; //最大値を返す
    }
}
class overload01 {
    public static void Main() {
        Maxs m = new Maxs();
        Console.WriteLine("Max(3, 2) = {0}", m.Max(3, 2)); //第1のバージョンが呼ばれる
        Console.WriteLine("Max(3, 4, 2) = {0}", m.Max(3, 4, 2)); //第2のバージョンが呼ばれる
        int[] ma = {3, 4, 8, 2};
        Console.WriteLine("Max(3, 4, 8, 2) = {0}", m.Max(ma)); //第3のバージョンが呼ばれる
    }
}

提出:アレンジ演習:p.195 overload01.cs

参考:効率アップバージョンの有効活用

・下記のシグニチャのMaxメソッドのオーバーロードを持つクラスMaxsを作成できる
 Max(int,int) //整数2値の最大値を返す
 Max(int,int,int) //整数3値の最大値を返す
 Max(double,duuble,duuble,duuble) //実数4値の最大値を返す
 Max(double[]) //実数配列の要素の最大値を返す

//参考:効率アップバージョンの有効活用
using System;
class Maxs {
    public int Max(int x, int y) { //①整数2値の最大値を返す
        double[] w = {x, y}; //2値を実数配列にして
        return (int)Max(w); //④を呼び、戻り値をintにキャストする
    }
    public int Max(int x, int y, int z) { //②整数3値の最大値を返す
        double[] w = {x, y, z}; //3値を実数配列にして
        return (int)Max(w); //④を呼び、戻り値をintにキャストする
    }
    public double Max(double x, double y, double z, double a) { //③実数4値の最大値を返す
        double[] w = {x, y, z, a}; //4値を配列にして
        return Max(w); //④を呼ぶ
    }
    public double Max(double[] a) { //④実数配列の最大値を返す
        double max = a[0]; //仮に先頭要素が最大とする
        for (int i = 1; i < a.Length; i++) { //先頭の次の要素から全要素について繰り返す
            if (max < a[i]) { //最大値超ならば
                max = a[i]; //最大値更新
            }
        }
        return max; //最大値を返す
    }
}
class overload01 {
    public static void Main() {
        Maxs m = new Maxs();
        Console.WriteLine("Max(3, 2) = {0}", m.Max(3, 2)); //第1のバージョンが呼ばれる
        Console.WriteLine("Max(3, 4, 2) = {0}", m.Max(3, 4, 2)); //第2のバージョンが呼ばれる
        Console.WriteLine("Max(3.3, 4.4, 2.2, 6.6) = {0}", m.Max(3.3, 4.4, 2.2, 6.6)); //第3のバージョンが呼ばれる
        Console.WriteLine("Max(3.3, 4.4, 8.8) = {0}", m.Max(new double[] {3.3, 4.4, 8.8})); //第4のバージョンが呼ばれる
    }
}

講義メモ

p.181「メソッドの再帰呼び出し」から

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

・C#などではメソッドの内部で自分自身を呼び出せる。これを再帰(リカージョン)といい、用いることでアルゴリズムをシンプルに表現できる
 場合がある
・なお、再帰のみを記述すると無限ループまたはメモリの使いつくしによる異常終了を起こすので、再帰を終わらせる条件が必要
・応用例:階乗(後述)、フィボナッチ数列(後述)、最大公約数、シェルソートなど

p.181 階乗を計算する

・ある整数nから1までの全整数の積をnの階乗といいn!と表す。
 例: 4! = 4×3×2×1 = 24、5! = 5×4×3×2×1 = 120
・よって、n! = n × (n - 1)! と、再帰で表すとシンプルで繰り返し構造が不要になる
・階乗のルールとして、0! = 1! = 1 があるので、これを再帰の終了条件に用いると良い

p.182 fact01.cs

//p.182 fact01.cs
using System;
class Fact { //インスタンスメソッドッドのみを含むクラス
    public long CalcFact(int n) { //再帰を含むインスタンスメソッドで階乗を返す
        long fact; //内部用のローカル変数
        if (n == 0) { //0!は固定なので再帰の終了条件に用いる
            fact = 1; //0! = 1
        } else {
            fact = n * CalcFact(n - 1); //n! = n×(n-1)!
        }
        return fact; //n!を返す
    }
}
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

・0! = 1のみならず、1! = 1であることを加えて実行効率を上げよう
・また、条件演算子を用いて記述をよりシンプルにしよう

作成例

//アレンジ演習:p.182 fact01.cs
using System;
class Fact { //インスタンスメソッドッドのみを含むクラス
    public long CalcFact(int n) { //再帰を含むインスタンスメソッドで階乗を返す
        return (n <= 1) ? 1 : n * CalcFact(n - 1); //【変更】
    }
}
class fact01 {
    public static void Main() {
        Fact f = new Fact();
        for (int i = 0; i <= 20; i++) {
            Console.WriteLine("{0,2}! = {1}", i, f.CalcFact(i));
        }
    }
}

p.185 fibonacci.cs

//p.185 fibonacci.cs
using System;
class fibo {
    public long CalcFibo(int n) {
        long fb;
        if (n == 1 || n == 2) { //再帰の終了条件
            fb = 1;
        } else {
            fb = CalcFibo(n - 1) + CalcFibo(n - 2); //再帰する
        }
        return fb;
    }
}
class fibonacci {
    public static void Main() {
        fibo f = new fibo();
        for (int i = 1; i <= 30; i++) {
            Console.WriteLine("f({0}) = {1}", i, f.CalcFibo(i));
        }
    }
}

アレンジ演習:p.185 fibonacci.cs

・条件演算子を用いて記述をよりシンプルにしよう

作成例

//アレンジ演習:p.185 fibonacci.cs
using System;
using System.Runtime.Remoting.Messaging;

class fibo {
    public long CalcFibo(int n) {
        return (n <= 2) ? 1L : (long)CalcFibo(n - 1) + CalcFibo(n - 2); //再帰する
    }
}
class fibonacci {
    public static void Main() {
        fibo f = new fibo();
        for (int i = 1; i <= 30; i++) {
            Console.WriteLine("f({0}) = {1}", i, f.CalcFibo(i));
        }
    }
}

p.188(値渡しと参照渡し)

・C#のメソッドの基本は値渡しであり、実引数の値が仮引数にコピーされるので、関数内部で仮引数の値を変更しても、呼び出し側の実引数には
 反映しない。
 ⇒ p.189 swap01.cs
・C#の参照型データにおいても値渡しになるので、参照型であるstring型の変数であっても参照渡しにはならない
 ⇒ p.190 swap02.cs
・なお、配列などのデータ構造を実引数にした場合、構造名が参照を示すので、参照がコピーされ、関数内部で仮引数のデータ構造をの中の値を
 変更すると、呼び出し側の実引数のデータ構造に反映する
 ※ returnする必要はない

p.191 charngearray01.cs

//p.191 charngearray01.cs
using System;
class change {
    public void modify(int[] array) { //引数が配列なの参照を受け取るメソッド
        int n = array.Length; //参照経由で実引数のプロパティ(後述)を実行して要素数が得られる
        for (int i = 0; i < n; i++) { //要素数を用いて全要素について繰り返す
            array[i] *= 2; //要素の値を書き換えるので実引数になっている配列の要素値も書き変わる
        }
    }
}
class changearray01 {
    public static void Main() {
        change c = new change(); //
        int[] myarray = new int[3]{1, 2, 3};
        Console.WriteLine("----modifyメソッド実行前----");
        int i = 0;
        foreach (int x in myarray) { //配列の全要素について繰り返す
            Console.WriteLine("myarray[{0}] = {1}", i, x);
            i++; //添字を扱えないのでカウンタの代わりに
        }
        c.modify(myarray);
        Console.WriteLine("----modifyメソッド実行後----");
        i = 0;
        foreach (int x in myarray) { //配列の全要素について繰り返す
            Console.WriteLine("myarray[{0}] = {1}", i, x);
            i++; //添字を扱えないのでカウンタの代わりに
       }
    }
}

アレンジ演習:p.191 charngearray01.cs

・配列の初期化をシンプルにし、foreachで添え字を扱うのは非効率なのでforにしよう

作成例

//アレンジ演習:p.191 charngearray01.cs
using System;
class change {
    public void modify(int[] array) { //引数が配列なの参照を受け取るメソッド
        int n = array.Length; //参照経由で実引数のプロパティ(後述)を実行して要素数が得られる
        for (int i = 0; i < n; i++) { //要素数を用いて全要素について繰り返す
            array[i] *= 2; //要素の値を書き換えるので実引数になっている配列の要素値も書き変わる
        }
    }
}
class changearray01 {
    public static void Main() {
        change c = new change();
        int[] myarray = {1, 2, 3}; //【変更】
        Console.WriteLine("----modifyメソッド実行前----");
        for (int i = 0; i < myarray.Length; i++) { //【変更】配列の全要素について繰り返す
            Console.WriteLine("myarray[{0}] = {1}", i, myarray[i]); //【変更】
        }
        c.modify(myarray);
        Console.WriteLine("----modifyメソッド実行後----");
        for (int i = 0; i < myarray.Length; i++) { //【変更】配列の全要素について繰り返す
            Console.WriteLine("myarray[{0}] = {1}", i, myarray[i]); //【変更】
        }
    }
}

p.18(ref)

・実引数を参照渡しにして、メソッド内部で仮引数の値を変更すると、呼び出し側の実引数に反映するのがref指定。
・実引数が単独の変数であり、実引数と仮引数の両方にref指定がされていることが必要だが、変数名は異なってOK
・関数側の書式例: アクセス修飾子 戻り値型 メソッド名(ref 型 仮引数名, …){…}
 ※ 戻り値型はvoidでも良い(するとreturn不要)。仮引数が複数ある場合、ref指定の有無が混在できる
・呼出側の書式例: メソッド名(ref 実引数である変数, …);
・ただし、実引数は初期化あるいは値の代入がされていること

p.193 swap03.cs

//p.193 swap03.cs
using System;
class myclass {
    private int temp; //内部の作業用の変数
    public void swap(ref int x, ref int y) { //ref指定の仮引数なので参照渡しになる
        temp = x;
        x = y; //書き換えたxの値は呼び出し元の変数に反映する
        y = temp; //書き換えたyの値は呼び出し元の変数に反映する
    }
}
class swap01 {
    public static void Main() {
        myclass s = new myclass();
        int x = 10, y = 20;
        s.swap(ref x, ref y); //ref指定の実引数なので参照渡しになる
        Console.WriteLine("x = {0}, y = {1}", x, y); //呼び出しによりxとyの値が交換されている
    }
}

アレンジ演習:p.193 swap03.cs

・実引数名と仮引数名を異なる名前にして、参照渡しの効果を見やすくしよう
・myclassクラスのインスタンス変数tempは(インスタンス変数である必要がないので)ローカルのvar型にしよう

作成例

//アレンジ演習:p.193 swap03.cs
using System;
class myclass {
    public void swap(ref int x, ref int y) { //ref指定の仮引数なので参照渡しになる
        var temp = x; //【変更】一時的変数にxの値を退避する
        x = y; //書き換えたxの値は呼び出し元の変数に反映する
        y = temp; //書き換えたyの値は呼び出し元の変数に反映する
    }
}
class swap01 {
    public static void Main() {
        myclass s = new myclass();
        int a = 10, b = 20;
        s.swap(ref a, ref b); //ref指定の実引数なので参照渡し(a⇔x、b⇔y)になる
        Console.WriteLine("a = {0}, b = {1}", a, b); //呼び出しによりxとyの値が交換されている
    }
}

p.194(outキーワードによる参照渡し)」

・refキーワードの強化版で「実引数は初期化あるいは値の代入がされていること」が不要になる
・outキーワードを指定したメソッドの呼び出し以降であれば、実引数の値を利用できる
 ※ ただし、利用可否と動作はC#のバージョンに依存するので、バージョン7より前では使えないので注意
 ※ また、out指定にした仮引数は初期化あるいは値の代入がされていないという前提で扱われるので、代入の右辺などに用いるとエラーになる。
 この場合はrefにすること

アレンジ演習 p.193 swap03.cs

・refをoutに変えるとエラーになることを確認しよう
・「temp = x;」「x = y;」は、xおよびyが初期化あるいは値の代入がされていない可能性があるのでエラーになる

作成例(エラーになる)

//アレンジ演習:p.193 swap03.cs
using System;
class myclass {
    public void swap(out int x, out int y) { //【変更】out指定の仮引数なので参照渡しになる
        var temp = x; //【エラー】xが初期化されていない可能性があるので代入不可
        x = y; //【エラー】yが初期化されていない可能性があるので代入不可
        y = temp; //書き換えたyの値は呼び出し元の変数に反映する
    }
}
class swap01 {
    public static void Main() {
        myclass s = new myclass();
        int a = 10, b = 20;
        s.swap(out a, out b); //out指定の実引数なので参照渡し(a⇔x、b⇔y)になる
        Console.WriteLine("a = {0}, b = {1}", a, b); //呼び出しによりxとyの値が交換されている
    }
}

p.194 outkeyword01.cs

//p.194 outkeyword01.cs
using System;
class MyClass {
    public void Square(double x, double y, out double s) { //仮引数sは参照渡し
        s = x * y; //代入の左辺なので初期化されていなくても良い
    }
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25, c;
        MyClass mc = new MyClass();
        //cには値を代入していません
        mc.Square(a, b, out c); //実引数cは結果の受け取り用なので初期化不要
        Console.WriteLine("縦{0}m, 横{1}mの長方形の面積は{2}平方メートル", a, b, c);
    }
}

アレンジ演習:p.194 outkeyword01.cs

・この場合、outキーワードも、それをつけた引数も不要で、returnでできることを確認しよう

作成例

//アレンジ演習:p.194 outkeyword01.cs
using System;
class MyClass {
    public double Square(double x, double y) { //【変更】
        return x * y; //【変更】
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25; //【変更】
        MyClass mc = new MyClass();
        Console.WriteLine("縦{0}m, 横{1}mの長方形の面積は{2}平方メートル", a, b, mc.Square(a, b)); //【変更】
    }
}

アレンジ演習:p.194 outkeyword01.cs

・outキーワードが便利な例として、2実数の和と積を返すメソッド 
 public void AddMul(double x, double y , out double sum, out double mul) 
 にしてみよう

作成例

//アレンジ演習:p.194 outkeyword01.cs
using System;
class MyClass {
    public void AddMul(double x, double y , out double sum, out double mul) { //【変更】
        sum = x + y; mul = x * y; //【変更】
    }
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25, c, d; //【変更】
        MyClass mc = new MyClass();
        mc.AddMul(a, b, out c, out d); //【変更】
        Console.WriteLine("和は{0}, 積は{1}", c, d); //【変更】
    }
}

今週の話題

販売本数ランキング 今回トップは「ピクミン4(Switch)」GO!
上場以来初の赤字に転落したUUUM、勝ち筋は利益率重視の「IP戦略」か【ゲーム企業の決算を読む】GO!
PS5の実売台数4,000万台達成!コミュニティーが選ぶ40タイトルも公開 GO!
クリエイターのための世界観「ISEKAI CREATORS」の『RPG Maker Unite』製サンプルゲーム公開―『RPG Maker MV/MZ』用DLCのSteam販売も開始 GO!
iOS 17にも「ゲームモード」開発中?AirPodsや無線コントローラが低遅延に、ベータから手がかり GO!
テーマは「コントロール」―UE使用作品制作ミニコンテスト「第20回UE5ぷちコン」エントリー受付中 GO!
サイバーエージェント、ゲーム事業で1億円の赤字 「ウマ娘」ヒット以来初の赤転 バブル崩壊か GO!
Microsoft決算は増収増益 「Azure OpenAI」の顧客は1万1000社超え GO!
Alphabet(google)決算は増収増益 クラウドの売上高が28%増と好調な他、YouTube広告も復調 GO!

「ちょっとした改変」も厳禁…Blizzardが『ディアブロ IV』Mod使用者をBANする方針を改めて明示 GO!
中国で『原神』チート開発・販売に関わった2名が逮捕―「リーク」に対する取り締まりも強化か GO!
金曜ドラマで“本物”のハッキングシーン 手口もコマンドも専門家が監修した「トリリオンゲーム」GO!
「マルウェア入り画像」で生成AIにサイバー攻撃 入力すると回答結果をハック、悪意サイトへの誘導も GO!

前回のコメント

・まだオーバーロードやらシグニチャやらこんがらがってる感じです。
 整理しながらプログラムを打てるようになりたいと思いました。

 テキストの記述に偏りがあること(例:メソッドのオーバーロードの記述不足)も原因ですね。
 繰返しフォローしますので、知識の整理を進めてください。

講義メモ 後半

p.174 this

・自分自身を指す参照を与えるキーワードがthis
・クラス内で自分自身を指す参照を代入したり、操作に用いたい場合に利用できる

p.174 this01.cs

//p.174 this01.cs
using System;
class MyClass {
    public MyClass m1, m2; //自分のクラスを型とする参照変数(インスタンス変数)
    public void Test() { //インスタンスメソッド
        m2 = this; //自分自身を指す参照を代入
    }
    public MyClass() { //コンストラクタ
        m1 = this; //自分自身を指す参照を代入
    }
}
class this01 {
    public static void Main() {
        MyClass mc = new MyClass(); //オブジェクトを生成しコンストラクタを呼ぶ(m1にthisが代入される)
        mc.Test(); //m2にthisが代入される
        if (mc.m1 == mc.m2) //インスタンス変数どうしを比較(どちらもthisが代入されているので等しい)
            Console.WriteLine("m1とm2は同じです");
        if (mc == mc.m1) //自分自身とインスタンス変数m1を比較(thisが代入されているので等しい)
            Console.WriteLine("mcとm1は同じです");
        if (mc == mc.m2) //自分自身とインスタンス変数m2を比較(thisが代入されているので等しい)
            Console.WriteLine("mcとm2は同じです");
    }
}

参考:thisの活用法

・thisが自分自身(自オブジェクト)を指すことを利用して、インスタンス変数を扱うメソッドの引数名を変数名と同じにできる
例:
class Monster {
  int hp, mp;
  void setHp(int hp) { this.hp = hp; } //「hp = hp」はエラーなのでこうすると良い
  void setMp(int mp) { this.mp = mp; } //「mp = mp」はエラーなのでこうすると良い
}

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

・すでに利用しているConsole.Writeや、Math.PIは特殊なクラスの利用例(静的メソッド/データメンバ)
・ここまで用いたインスタンス変数やインスタンスメソッドを持つ既存のクラスも多数ある
・その1つがArrayListクラスで、利用には「using System.Collections;」を指定すること。
・ArrayListクラスは必要に応じてサイズが動的に拡大される配列を提供するもので、各種のメソッドが利用できる
 ・デフォルトコンストラクタ:空で、既定の初期量を備えた、ArrayList クラスの新しいインスタンスを初期化
 ・add(object)メソッド:要素を末尾に格納する(どんな型でもOK)
 ・Countプロパティ:要素数を返す(プロパティは特殊なメソッド:p.207で後述)
 ・配列と同様に[n]で先頭から(先頭を0として)n番目の要素が得られる
 ・ただし、得られる要素はobject型なので、元の型にキャストして用いること

p.177 arraylist01.cs

//p.177 arraylist01.cs
using System;
using System.Collections;
class arraylist01 {
    public static void Main() {
        bool bEnd = false; //終了フラグをオフに
        string strData; //入力用
        double sum = 0.0; //合計
        ArrayList al = new ArrayList(); //アレイリストを生成
        while (true) { //無限ループ
            Console.Write("データ(数値以外入力で終了)-- ");
            strData = Console.ReadLine();
            if (!Char.IsDigit(strData[0]) && strData[0] != '-') { //先頭文字が数字でも-でもない
                bEnd = true; //終了フラグをオンに
            } else { //実数変換が可能?(※チェックとしては不十分)
                al.Add(double.Parse(strData)); //実数変換してアレイリストに格納
            }
            if (bEnd) { //終了フラグがオン?
                break; //無限ループを抜ける
            }
        }
        for (int i = 0; i < al.Count; i++) { //アレイリストの要素数だけ繰り返す
            Console.WriteLine("Data[{0}] = {1}", i + 1, al[i]); //番号i+1と要素[i]の値を表示
            sum += (double)al[i]; //要素[i]をdouble型に戻してから合計に足しこむ
        }
        int count = al.Count; //アレイリストの要素数を得る
        double avr = sum / count; //合計を要素数で割って平均値を得る
        Console.WriteLine("データ個数 = {0}", count); //要素数を個数として表示
        Console.WriteLine("平均値 = {0}", avr); //計算済の平均値を表示
    }
}

p.180 練習問題1 ヒント

・「インスタンス変数のみを持つクラス」とあるので、実行用のMainメソッドを持つクラスとは別に記述しよう
・「Mainメソッドからこのフィールドに数値を代入し」とあるので、public指定すること

作成例

// p.180 練習問題1
using System;
class MyInt {
    public int x; //外部からアクセスできるインスタンス変数
}
class ex071 {
    public static void Main() {
        MyInt m = new MyInt(); //オブジェクトを生成
        m.x = 10; //インスタンス変数に代入
        Console.WriteLine("m.x = {0}", m.x); //インスタンス変数の値を表示
    }
}

p.180 練習問題2 ヒント

・int型2値の和を得るメソッドの戻り値型はintに、double型2値の和を得るメソッドの戻り値型はdoubleにすると良い
・この2メソッドを同じ名前のメソッド(例:Add)にすると、オーバーロードになる
・「メソッドを持つクラス」とあるので、実行用のMainメソッドを持つクラスとは別に記述しよう
・「Mainメソッドからこれらのメソッドを利用」とあるので、2メソッドはpublic指定にすること

作成例

// p.180 練習問題2
using System;
class MyAdd {
    public int add(int i1, int i2) { //外部からアクセスできるインスタンスメソッド①
        return i1 + i2;
    }
    public double add(double i1, double i2) { //①をオーバーロードしているインスタンスメソッド②
        return i1 + i2;
    }
}
class ex072 {
    public static void Main() {
        MyAdd m = new MyAdd(); //オブジェクトを生成
        Console.WriteLine("1   + 2   = {0}", m.add(1, 2)); //メソッド①を呼んで戻り値を表示
        Console.WriteLine("1.1 + 2.2 = {0}", m.add(1.1, 2.2)); //メソッド②を呼んで戻り値を表示
    }
}

提出:p.180 練習問題2

講義メモ

・p.169「construct02.cs」から

p.168(コンストラクタの引数とオーバーロード:再掲載+α)

・コンストラクタもメソッドの一種なので、パラメータリストを指定できる
 例: public Monster(int h, int m) { hp = h; mp = m; }
・これはnewによって呼び出す時に、その値を指定する
 例: Monster rimuru = new Monster(100, 500); //コンストラクタにHPとMPを渡して初期値にしてもらう
・パラメータリストを指定したコンストラクタと指定しないコンストラクタを混在できる
・また、呼び出しにおいて区別できるのであれば、パラメータリストを指定したコンストラクタを複数記述できる
・このことをオーバーロードという(※メソッド全体に対応する)
・パラメータ(引数)の数、型、順序によって区別が可能であればいくつでも指定可能
例: 
  public Monster()                { hp = 10; mp = 20; } //コンストラクタ①
 public Monster(int h)           { hp = h;  mp = 20; } //コンストラクタ②
 public Monster(int h, int m)    { hp = h;  mp = m;  } //コンストラクタ③
  public Monster(string s)        { name = s;         } //コンストラクタ④
  public Monster(string s, int h) { name = s; hp = h; } //コンストラクタ⑤
  public Monster(int m, string s) { name = s; mp = m; } //コンストラクタ⑥
 :
  Monster veldra = new Monster(); //コンストラクタ①を呼ぶ
  Monster slalin = new Monster(100); //コンストラクタ②を呼ぶ
  Monster rimuru = new Monster(100, 500); //コンストラクタ③を呼ぶ
  Monster hoimin = new Monster("ほいみん"); //コンストラクタ④を呼ぶ
  Monster behoim = new Monster("べほいみん", 100); //コンストラクタ⑤を呼ぶ
  Monster behoma = new Monster(500, "べほま"); //コンストラクタ⑥を呼ぶ

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(); //年齢を文字列化
        Console.WriteLine("氏名:{0} 住所:{1} 年齢:{2}", name, address, toshi); //全ての値をそのまま表示(年齢が-1の時のみ加工)
    }
    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(); //1番目のインスタンスの変数値を表示
        mc2.Show(); //2番目のインスタンスの変数値を表示
        mc3.Show(); //3番目のインスタンスの変数値を表示
    }
}

p.169(シグニチャ)

・メソッド(コンストラクタ含む)の呼び出しパターンを説明するもの
・メソッド名(コンストラクタの場合はクラス名)とパラメータリストにある引数の型の並びが、シグニチャになる
 例: MyClass(string str1, string str2, int x) → MyClass(string, string, int)
・シグニチャが等しいメソッド(コンストラクタ)は同じ場には定義できない。
・なお、戻り値型はシグニチャに含まれないので、メソッドの場合に注意。

p.170(引数のあるコンストラクタと引数のないコンストラクタ)

・クラスにコンストラクタをまったく記述しないと「クラス名(){}」という中身がなく引数のないコンストラクタが自動作成される
・引数のあるコンストラクタを1つでも記述すると、↑の働きは起きないので、必要ならば自前で作成すること
・呼び出し時に引数をまったく指定しない時に、呼び出されるコンストラクタをデフォルトコンストラクタという。
・基本的には「引数のないコンストラクタ」=「デフォルトコンストラクタ」だが、後述の可変長引数(p.201)などを用いると、
 引数指定のあるデフォルトコンストラクタも記述可能。

p.171 デストラクタ

・プログラム内で生成されたオブジェクトは、基本的に完了時に消去される
・C#システムがメモリの残量を検知して、利用されないオブジェクトを削除する機能があり、これをガーベージ・コレクションともいう。
 ただし、その実行を依頼したり、実行をプログラムから制御することは不可。
・そして「オブジェクトの生成時に呼ばれる」コンストラクタと逆に「オブジェクトの消去時に呼ばれる」デストラクタがあり、
 実行は制御できないが、確実に実行できる、
 ※ よって、コンストラクタが行ったことの後始末に用いることもある(例:DB切断)
・複数のオブジェクトが破棄された場合、デストラクタの実行順序は不定。
・書式: ~クラス名() { 処理内容; }
・コンストラクタと同様に戻り値はなく、パラメータリストもない(よって、オーバーロードもない)

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生成");
    }
}

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

・string型のインスタンス変数を定義して、コンソールから入力し、オブジェクト生成時にコンストラクタ(文字列)から値を得よう
・デストラクタではその文字列を表示しよう
・なお、3つのオブジェクトはどれも同じ参照変数dt1を用いること(こうしてもデストラクタは3回動作する)

作成例

//アレンジp.172 destruct01.cs
using System;
class DestructTest {
    string x; //インスタンス変数
    // デストラクタ
    ~DestructTest() {
        Console.WriteLine(x);
    }
    // 引数付きコンストラクタ
    public DestructTest(string n) {
        x = n; 
    }
}
class destruct {
    public static void Main() {
        Console.Write("dt1の断末魔:");
        DestructTest dt1 = new DestructTest(Console.ReadLine());
        Console.Write("dt2の断末魔:");
        dt1 = new DestructTest(Console.ReadLine()); //この時点で1つめのオブジェクトは利用不能になるが存続する
        Console.Write("dt3の断末魔:");
        dt1 = new DestructTest(Console.ReadLine()); //この時点で2つめのオブジェクトも利用不能になるが存続する
    } //終了時点で3つ分のデストラクタが動作する
}

今週の話題

販売本数ランキング 今回トップも「ゼルダの伝説 ティアーズ オブ ザ キングダム(Switch)」GO!
KADOKAWAはアニメ発のゲーム開発でヒットの再現性を高められるか【ゲーム企業の決算を読む】GO!
インディーゲーム/VTuberのモーションキャプチャも低価格で提供ー「MyDearestモーキャプスタジオ」一般向けにレンタル開始 GO!
Mint Town、10億円の資金調達を実施―ゲームクリエイターを中心に採用強化 GO!
グリー子会社REALITY XR cloud、『スタディサプリ ENGLISH for KIDS』に開発協力 GO!

「ROG Ally」注目デバイス故か…過去にもDualSenseドリフト問題など提起の米法律事務所が不具合の情報提供呼びかけへ―集団訴訟へ発展の可能性も GO!
ガチャは子供に悪影響?英国ゲーム業界がルートボックスを制限する業界原則を発表―確率開示や返金の容易化を含む11項目 GO!

前回のコメント

・まだまだ引数やインスタンス変数などの用語がごっちゃになることがありますが
 少しずつ慣れるように頑張りたいと思いました。
 次のデストラクタ(断末魔)も楽しみです!ひでぶーー

 是非、応援します&お楽しみに♪