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

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

・C#などでは、メソッドの内部で自分自身を呼び出すことができる。これを再帰(リカージョン)という
・再帰を用いることで、アルゴリズムをシンプルに表現できる場合があり、重宝されている。
・ただし、再帰のみを記述する無限ループになり、戻り情報を残しながら繰返すので、これに用いられるスタックメモリの使いつくしによる
 異常終了となる
・そこで、終了条件を記述する必要がある
・基本的構文: メソッド名(引数①) { if(終了条件?) { return 値; } else { return メソッド名(引数②); }
・見かけ上は繰返しではないが、自分を呼び出すことでループ構造になることに注意

p.181 階乗を計算する(メソッドの再帰呼び出しの一例)

・ある整数nから1までの全整数の積を、nの階乗といい、整数!で示す
・例: 2! = 2、 3! = 6、4! = 24、5! = 120
・よって、階乗の計算式は n! = n * (n-1) * (n-2) * (n-3) * … * 2 であり、
 (n - 1)! = (n-2) * (n-3) * … * 2 だから、
 n! = n * (n-1)! と表すことができるので再帰呼び出しになる
・そして、階乗のルールとして、0!は1、1!は1 なので、これらを再帰の終了条件にすれば良い

アレンジ演習:p.183

・表示の桁数を設定し、再帰の回数も表示するようにしよう
・publicインスタンス変数cntを0で初期化し、再帰呼び出し時にインクリメントし、結果表示時に併記すれば良い

 0! =                    1,   0
 1! =                    1,   1
 2! =                    2,   3
 3! =                    6,   6
 4! =                   24,  10
 5! =                  120,  15
 6! =                  720,  21
 7! =                 5040,  28
 8! =                40320,  36
 9! =               362880,  45
10! =              3628800,  55
11! =             39916800,  66
12! =            479001600,  78
13! =           6227020800,  91
14! =          87178291200, 105
15! =        1307674368000, 120
16! =       20922789888000, 136
17! =      355687428096000, 153
18! =     6402373705728000, 171
19! =   121645100408832000, 190
20! =  2432902008176640000, 210

・それから、nが1の場合も1を返すようにして、再帰の回数が減ることを確認しよう

 0! =                    1,   0
 1! =                    1,   0
 2! =                    2,   1
 3! =                    6,   3
 4! =                   24,   6
 5! =                  120,  10
 6! =                  720,  15
 7! =                 5040,  21
 8! =                40320,  28
 9! =               362880,  36
10! =              3628800,  45
11! =             39916800,  55
12! =            479001600,  66
13! =           6227020800,  78
14! =          87178291200,  91
15! =        1307674368000, 105
16! =       20922789888000, 120
17! =      355687428096000, 136
18! =     6402373705728000, 153
19! =   121645100408832000, 171
20! =  2432902008176640000, 190

作成例

//アレンジ演習:p.182 fact01.cs
using System;
class Fact { 
    public int cnt = 0; //【追加】再帰の回数
    public long CalcFact(int n) { //再帰呼び出しされるメソッド
        long fact; //階乗用
        if (n == 0 || n == 1) { //【変更】0!または1!であれば(終了条件)
            fact = 1; //階乗は1
        } else { //でなければ
            cnt++; //【追加】再帰の回数カウントアップ
            fact = n * CalcFact(n - 1); //階乗は義に従い n × (n-1)!
        }
        return fact; //階乗を返す
    }
}
class fact01 {
    public static void Main() {
        Fact f = new Fact();
        for (int i = 0; i <= 20; i++) { //0!から20!まで
            Console.WriteLine("{0,2}! = {1,20}, {2,3}", i, f.CalcFact(i), f.cnt); //【変更】
        }
    }
}

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

・変数factを用いずに、結果を直接returnしても同じ動作になることを確認しよう

作成例

//アレンジ演習:p.182 fact01.cs
using System;
class Fact { 
    public int cnt = 0; //再帰の回数
    public long CalcFact(int n) { //再帰呼び出しされるメソッド
        if (n == 0 || n == 1) { //0!または1!であれば(終了条件)
            return 1; //【変更】階乗は1
        } else { //でなければ
            cnt++; //再帰の回数カウントアップ
            return n * CalcFact(n - 1); //【変更】階乗は定義に従い n × (n-1)!
        }
    }
}
class fact01 {
    public static void Main() {
        Fact f = new Fact();
        for (int i = 0; i <= 20; i++) { //0!から20!まで
            Console.WriteLine("{0,2}! = {1,20}, {2,3}", i, f.CalcFact(i), f.cnt);
        }
    }
}

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

・条件演算子を用いて、さらにシンプルにしよう(回数の表示は割愛してOK)

作成例

//アレンジ演習:p.182 fact01.cs
using System;
class Fact { 
    public long CalcFact(int n) { //再帰呼び出しされるメソッド
        return (n <= 1) ? 1 : n * CalcFact(n - 1); //【変更】1以下の階乗は1、でなければ n × (n-1)!
    }
}
class fact01 {
    public static void Main() {
        Fact f = new Fact();
        for (int i = 0; i <= 20; i++) { //0!から20!まで
         &nbs候補はありWriteLine("{0,2}! = {1,20}", i, f.CalcFact(i)); //【変更】
        }
    }
}

p.185 フィボナッチ数列を求める

・フィボナッチ数列とは、1番目と2番目は1で、3番目以降は前2つの和になっている数列
・よって、n番目の値は(n-1)番目の値と(n-2)番目の値の和なので、再帰で表すことができる
・つまり、n番目の値を得るメソッドは:
 メソッド(n) { return (n <= 2) ? 1 : メソッド(n-1) + メソッド(n-2); }

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

・上記の例の通り、条件演算子を用いてシンプルにしよう

作成例

//アレンジ演習:p.167 fibonacci.cs
using System;
class fibo {
    public long CalcFibo(int n) {
        return (n <= 2) ? 1 : CalcFibo(n - 1) + CalcFibo(n - 2); //1,2番目は1で、3番目以降は前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 refとout(値渡しと参照渡し)

・p.189のswap01.csの説明にある通り、C#のメソッドにおける引数は「値のコピーが渡される」
・よって、メソッド中で引数の値を書き換えても、元の値は変わらない
・このことを「値渡し」といい、安全性を高めている
・言語によっては、参照型データにおいて「値渡し」にはならない場合があるがC#では参照型データも「値渡し」
 ⇒ p.190 swap02.cs
・対して、配列などのデータ構造を引数にすると「値のコピーが渡す」のではなく、効率性のために、参照(構造の位置情報)が渡される
・このことを「参照渡し」といい、大きな構造を渡す場合の効率を高めている
 ⇒ p.191 changearray01.cs
・「参照渡し」にすると、引数を値の受け渡しに利用できるので、returnを用いずに結果を返すことができ、しかも2個以上の情報を返す
 ことが可能
・例:配列[0]と[1]の和を[2]に、差を[3]に、積を[4]に格納するメソッド

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

・引数の配列[0]と[1]の和を[2]に、差を[3]に、積を[4]に格納するメソッドにしてみよう

作成例

//アレンジ演習: p.191 charngearray01.cs
using System;
class change {
    public void modify(int[] array) { //配列を参照渡しで受け取って書き換えるメソッド
        array[2] = array[0] + array[1]; //配列[0]と[1]の和を[2]に格納する 
        array[3] = (array[0] > array[1]) ? array[0] - array[1] : array[1] - array[0]; //差を[3]に格納する 
        array[4] = array[0] * array[1]; //積を[4]に格納する 
    }
}
class changearray01 {
    public static void Main(){
        change c = new change();
        int[] a = {10, 20, 0, 0, 0};
        c.modify(a); //配列を参照渡しで渡して書き換えてもらう
        Console.WriteLine("{0}と{1}の和は{2},差は{3},積は{4}", a[0], a[1], a[2], a[3], a[4]);
    }
}

p.192 ref

・値において、呼び出し側の引数(実引数)とメソッド側の引数(仮引数)の両方に「ref」キーワードをつけると、
 値渡しではなく参照渡しになる
・呼び出し側の書式: メソッド名(ref 実引数, …)
・メソッド側の書式: 戻り値型 メソッド名(ref 仮引数, …) {…}
・呼び出し側の実引数は変更可能な変数であること(式や定数やリテラルやデータ構造を渡すことはできない)
・実引数と仮引数の名前は異なって良い
・複数の引数がある場合、ref付きとref無しが混在しても良い
・なお、実引数は初期化または値の代入がされていることが条件

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

・2実数を受け取るオーバロードメソッド void Swap(ref double x, ref double y) を追記しよう
・そして、double d1 = 3.14, d2 = 2.2 をref付きで渡して、実引数と仮引数の名前が異なっても動作することを確認しよう

作成例

//アレンジ演習:p.193 swap03.cs
using System;
class myclass {
    public void swap(ref int x, ref int y) { //2引数を参照渡しで扱うメソッド
        int temp = x; //【変更】メソッド内での初期化に変更
        x = y; //2引数の値を交換
        y = temp;
    }
    public void swap(ref double x, ref double y) { //【以下追加】2引数を参照渡しで扱うメソッドのオーバロード
        double temp = x;
        x = y; //2引数の値を交換
        y = temp;
    }
}
class swap01 {
    public static void Main() {
        myclass s = new myclass();
        int x = 10, y = 20;
        s.swap(ref x, ref y); //2引数を参照渡しでメソッドに渡す
        Console.WriteLine("x = {0}, y = {1}", x, y); //2引数の値が交換されている
        double d1 = 3.14, d2 = 2.2; //【以下追加】
        s.swap(ref d1, ref d2); //2引数を参照渡しでオーバロードメソッドに渡す
        Console.WriteLine("d1 = {0}, d2 = {1}", d1, d2); //2引数の値が交換されている
    }
}

ミニ演習 mini193.cs

・アレンジ演習:p.191 changearray01.csを元に、引数のaとbの和をref waで、差をref saで、積をref seiで返すメソッドにしてみよう
 void modify(int a, int b, ref int wa, ref int sa, ref int seki){…}

作成例

//ミニ演習 mini193.cs
using System;
class change {
    public void modify(int a, int b, ref int wa, ref int sa, ref int seki) { //aとbの和差積を返すメソッド
        wa = a + b; //和を格納する 
        sa = (a > b) ? a - b : b - a; //差を格納する 
        seki = a * b; //積を格納する 
    }
}
class changearray01 {
    public static void Main(){
        change c = new change();
        int x = 0, y = 0, z = 0;
        c.modify(10, 20, ref x, ref y, ref z); //参照渡しで和差積を書きこんでもらう
        Console.WriteLine("{0}と{1}の和は{2},差は{3},積は{4}", 10, 20, x, y, z);
    }
}

p.194 out

・実引数の初期化または値の代入がされていなくても参照渡しが可能なのがoutキーワード
・C#のバージョン7以降で利用可能
・refの代わりに利用できるが「初期化または値の代入がされていない変数」とみなされるので、
 outキーワード付きの仮引数は代入の右辺や表示には使えない
 ⇒ よって、swap03.csのrefをoutに書き換えるとエラーになる
・つまり、refを置き換えるものではなく、処理内容によって使い分けること

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

・外周(縦の倍+横の倍)もoutで返すようにしよう

作成例

//アレンジ演習:p.194 outkeyword01.cs
using System;
class MyClass {
    public void Square(double x, double y, out double s, out double o) { //outでの参照渡しがあるメソッド
        s = x * y; //仮引数sは左辺ならOK
        o = x * 2 + y * 2; //仮引数oは左辺ならOK
    }
}
class outkeyword01 {
    public static void Main() {
        double a = 125.3, b = 16.25, c, d; //c,dには値を代入していません
        MyClass mc = new MyClass();
        mc.Square(a, b, out c, out d); //縦横を渡して面積と外周を得るメソッド
        Console.WriteLine("縦{0}m, 横{1}mの長方形の面積は{2}平方cm,外周は{3}cm", a, b, c, d);
    }
}

提出:ミニ演習 mini193.cs・改

・アレンジ演習:p.191 changearray01.csを元に、引数のaとbの和をout waで、差をout saで、積をout seiで返すメソッドにしてみよう
 void modify(int a, int b, out int wa, out int sa, out int seki){…}

講義メモ

・p.180「第7章 練習問題」から

提出フォロー:アレンジ演習:p.177 arraylist01.cs

・終了フラグを用いないようにしよう
・foreachが利用できるか試してみよう

作成例

//アレンジ演習:p.177 arraylist01.cs
using System;
using System.Collections;
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] != '-') { //先頭文字が数字でなく-でもない?
                break; //【変更】ループを抜ける
            } else {
                al.Add(double.Parse(strData)); //ArrayList配列に格納
            }
        }
        int i = 0; //【追加】
        foreach (var w in al) { //【変更】ArrayList配列の全データについて繰返す
            Console.WriteLine("Data[{0}] = {1}", ++i, w); //【変更】
            sum += (double)w;  //【変更】実数に戻して合計に足し込む
        }
        int count = al.Count; //ArrayList配列の要素数を得る
        double avr = sum / count; //合計を割って平均値を得る
        Console.WriteLine("データ個数 = {0}", count);
        Console.WriteLine("平均値 = {0}", avr);
    }
}

p.180 練習問題1 ヒント

・クラス定義の例: class MyClass { public int n; }

作成例

//p.180 練習問題1 
using System;
class MyClass { //int型のpublic変数のみを持つクラス
    public int n; 
}
class arraylist01 {
    public static void Main() {
        MyClass m = new MyClass();
        m.n = 1;
        Console.WriteLine(m.n);
    }
}

p.180 練習問題2 ヒント

・int型とint型の和を求めるメソッドの戻り値型はint型にすると良い
・double型とdouble型の和を求めるメソッドの戻り値型はdouble型にすると良い
・上記はMainメソッドから利用するので、publicにすると良い

作成例

//p.180 練習問題2
using System;
class MyClass { //int型のpublic変数のみを持つクラス
    public int add(int a, int b) { //メソッド①
        return a + b;
    }
    public double add(double a, double b) { //①のオーバロード
        return a + b;
    }
}
class arraylist01 {
    public static void Main() {
        MyClass m = new MyClass();
        Console.WriteLine("{0} + {1} = {2}", 10, 20, m.add(10, 20)); //メソッド①を利用
        Console.WriteLine("{0} + {1} = {2}", 3.1, 3.2, m.add(3.1, 3.2)); //オーバロードを利用
    }
}

今週の話題

ゲームソフト販売本数ランキング:今週1位は再び「スーパー マリオパーティ ジャンボリー(Switch)」 GO!
KRAFTONが2024年度に過去最大の売上を達成―『PUBG』が破竹の勢いで拡大続く GO!
マーベラス、売上下方修正―社長退任へ、IPポートフォリオ再構築が課題【ゲーム企業の決算を読む】GO!
GameWith、メディア事業の広告単価減少止まらず…ゲーム決済アプリは活路となるか?【ゲーム企業の決算を読む】GO!
テイクツーの2025年度第3四半期は堅調な売上を達成―『NBA 2K25』が大きく貢献 GO!
アメリカのクレーンゲームブームを受けてラウンドワンの業績が急伸【ゲーム企業の決算を読む】GO!

Steamでリリースされたゲーム「PirateFi」からマルウェア検出―Valveは当該作品起動ユーザーに警告メール GO!

参考:文化庁メディア芸術クリエイター育成支援事業イベント GO!

前回のコメント

・理解できた

 何よりです。

・本日はありがとうございました。
・今日もありがとうございました。次も頑張ります。

 応援します。

・今回もありがとうございました。
 練習問題は来週までに時間があり次第チャレンジしてみようと思います

 次回説明しますが、少し難しいので、是非、予習しておいてください。

前回のコメントのうち、リクエストについて

・先生のプログラムを見ながら作ったのですが、繰り返しができなくなってしまいました。
 原因教えてもらえるとありがたいです。

 if文の条件の冒頭の「!」が抜けているので、
 「先頭文字が数字でなく-でもない?」が「先頭文字が数字、かつ、-ではない?」になっているのが原因です。

講義メモ 後半

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)
            Console.WriteLine("m1とm2は同じです");
        if (mc == mc.m1) //mcは自オブジェクトなのでm1、m2と同じ
            Console.WriteLine("mcとm1は同じです");
        if (mc == mc.m2) //同上
            Console.WriteLine("mcとm2は同じです");
    }
}

補足:thisの活用法① 自オブジェクトのデータを書き換えた結果を返すメソッド

・thisを使わずに自分のHPを倍にすると、単独で実行するしかない

class Monster {
   public int hp;
   public void hpx2() { hp = hp * 2; }
}
:
Monster slalin = new Monster();
slalin.hp = 100;
slalin.hpx2(); //200になる
slalin.hpx2(); //400になる
slalin.hpx2(); //800になる
Console.WriteLine(slalin.hp);

・thisを使って自分のHPを倍にすると、メソッドの結果をメソッドに渡すことで効率化できる

class Monster {
   public int hp;
   public Monster hpx2() { hp = hp * 2; return this; } //HPを2倍し、自分への参照を返す
}
:
Monster slalin = new Monster();
slalin.hp = 100;
slalin.hpx2().hpx2().hpx2(); //800になる
Console.WriteLine(slalin.hp);

・応用例

using System;
class Monster {
   public int hp, mp;
   public Monster hpx2() { hp = hp * 2; return this; }
   public Monster mpx2() { mp = mp * 2; return this; }
}
class this01 {
    public static void Main() {
        Monster slalin = new Monster();
        slalin.hp = 100;
        slalin.mp = 150;
        slalin.hpx2().hpx2().hpx2().mpx2(); //HPは800、MPは300になる
        Console.WriteLine("{0},{1}", slalin.hp, slalin.mp);
    }
}

補足:thisの活用法② インスタンス変数を用いるメソッドやコンストラクタの引数名を変数名と同じにできる

・下記のように「this.」はインスタンス変数、そうでない方は引数。

class Monster {
   public int hp, mp;
   public Monster(int hp) { this.hp = hp; }
   public void addmp(int mp) { this.mp += mp; }
}

※ この記述スタイルの利用をチームルールにしている場合もある

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

・C#が提供するArrayListクラスには、コンストラクタやインスタンス変数、インスタンスメソッドなどがある
 https://learn.microsoft.com/ja-jp/dotnet/api/system.collections.arraylist
・ArrayListクラスは必要に応じてサイズが動的に拡大されるArrayList配列を提供してくれる
・利用には、using System.Collections; を指定すると良い
・ArrayList配列の生成は、ArrayListクラスのデフォルトコンストラクタを呼ぶだけで良い(生成時の型指定は不要)
・ArrayList配列への要素の格納は、参照変数.Add(要素) で良く、要素の型は自由
・ArrayList配列の要素は配列と同様に 参照変数[添字] で直接扱える。
・ただし、型情報を失っているので、計算などにはキャストしてから扱うこと
・ArrayList配列の要素数は、参照変数.Count で得られる(プロパティ(p.207))

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(); //ArrayList配列を生成
        while (true) { //無限ループ
            Console.Write("データ(数値以外入力で終了)-- ");
            strData = Console.ReadLine();
            if (!Char.IsDigit(strData[0]) && strData[0] != '-') { //先頭文字が数字でなく-でもない?
                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

・終了フラグを用いないようにしよう
・foreachが利用できるか試してみよう

p.180 練習問題1 ヒント

・クラス定義の例: class MyClass { public int n; }

p.180 練習問題2 ヒント

・int型とint型の和を求めるメソッドの戻り値型はint型にすると良い
・double型とdouble型の和を求めるメソッドの戻り値型はdouble型にすると良い
・上記はMainメソッドから利用するので、publicにすると良い

講義メモ

・「p.168 コンストラクタ:コンストラクタのオーバーロード」から

p.167 コンストラクタ:コンストラクタの引数(再掲載)

・メソッドと同様にコンストラクタにも引数が指定できる
・引数を指定したコンストラクタを呼び出すには、newにおいてカッコ内に引数型と引数を記述する
・定義書式②: public クラス名(引数型 引数名, …) {処理内容}
 例: public Slime(int h, int p) { hp = h; mp = p; }
・呼び出し法: new クラス名(値や式, …);

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

・コンストラクタを含むメソッドは、引数で呼び出し方を区別できるのであれば、同じ名前で定義しても良い
※ C++の関数も同様だが、C言語などの関数では不可
・「呼び出し方を区別できる」とは、引数の数や引数型や順番の違いのこと
・この「引数の数や引数型や順番の違う」コンストラクタのことをコンストラクタのオーバーロードという
・例: public Monster(){…} //①引数のないコンストラクタ
・例: public Monster(int hp){…} //②HPのみを引数で渡すコンストラクタ
・例: public Monster(int hp, int mp){…} //③HPとMPを引数で渡すコンストラクタ
・例: public Monster(string name){…} //④nameのみを引数で渡すコンストラクタ
・上記は呼び出し方によって自動的に使い分けられる
・例: Monster Slalin = new Monster(); //①が呼ばれる
・例: Monster Hoimin = new Monster(20); //②が呼ばれ、20はHPに用いられる
・例: Monster Rimuru = new Monster(100, 200); //③が呼ばれ、100はHPに、200はMPに用いられる
・例: Monster Veldra = new Monster("ヴェルドラ"); //④が呼ばれ、"ヴェルドラ"は名前に用いられる
・メソッドのオーバーロードの場合、名前と引数の数や引数型や順番の違いで判別する
・この「名前が同じで、引数の数や引数型や順番の違う」メソッドのことをメソッドのオーバーロードという
・例: public void add(){…} //①引数のないメソッド
・例: public void add(int hp){…} //②HPのみを引数で渡すメソッド
・例: public void add(int hp, int mp){…} //③HPとMPを引数で渡すメソッド
・上記は呼び出し方によって自動的に使い分けられる
・例: add(); //①が呼ばれる
・例: add(20); //②が呼ばれ、20はHPに用いられる
・例: add(100, 200); //③が呼ばれ、100はHPに、200はMPに用いられる
・なお、メソッド名と、引数の数や引数型や順番の情報を合わせて、メソッドのシグニチャという
・コンストラクタは戻り値がないが、メソッドの戻り値型はオーバーロードのシグニチャに含まれない
・戻り値型のみが異なる場合、呼び出し方によって自動的に使い分けることはできないので、エラーになる
・例: public int add(int hp, int mp){…} //④エラー(③と同じシグニチャなので)

アレンジ演習: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) {
            toshi = "不明";
        } else { 
            toshi = age.ToString(); //整数を文字列に変換するメソッド(Int32クラス)
        }
        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; 
        address = "不定"; 
        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(); 
        MyClass mc4 = new MyClass("ヴェルファイア", 200); //【以下追加】コンストラクタ④(文字列,整数列)が呼ばれる
        mc4.Show();
    }
}

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

・通常、デフォルトコンストラクタは自動的に用意される
・自前で記述することもできる
・なお、コンストラクタのオーバーロードがされている場合、デフォルトコンストラクタは自動的に用意されない
・よって、自前で記述する必要がある

アレンジ演習: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) {
            toshi = "不明";
        } else { 
            toshi = age.ToString(); //整数を文字列に変換するメソッド(Int32クラス)
        }
        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; 
        address = "不定"; 
        age = x; 
    }
    public MyClass() { //デフォルトコンストラクタ⑤()
        name = "不明"; 
        address = "不定"; 
        age = -1; 
    }
}
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(); 
        MyClass mc4 = new MyClass("ヴェルファイア", 200); //コンストラクタ④(文字列,整数列)が呼ばれる
        mc4.Show();
        MyClass mc5 = new MyClass(); //【以下追加】デフォルトコンストラクタ⑤が呼ばれる
        mc5.Show();
    }
}

p.171 デストラクタ(デストラクタ)

・プログラムの中で生成されたオブジェクト(インスタンス)は、基本的に、プログラムの終了時に破棄される
・C#では、プログラマが意図的にオブジェクト(インスタンス)を削除(無効化)しても、即時には処理されない
・C#などではガベージコレクション機能があり、システム側で適時にオブジェクトの掃除を行うことで、メモリの利用効率を高めている
・なお、プログラム内でガベージコレクション機能を実行させることはできない
・参照されなくなったオブジェクトはガベージコレクションの対象になるので、参照を空にしたり、他のオブジェクトを指すようにすることで、
 オブジェクトを実質的に消すことは可能。
・例: Monster m = new Monster(); Monster n = new Monster(); m = n; //最初のnewで生成したオブジェクトmは消される

p.171 デストラクタ(ガベージコレクション)

・オブジェクトの生成時に呼ばれるコンストラクタに対して、オブジェクトの消去時に呼ばれる特殊なメソッドがデストラクタ
・デストラクタを直接呼び出したり、動作タイミングを成業することはできない(ガベージコレクションと同様)
・デストラクタは内容が空のものが自動的に用意されるが自前で記述することもできる
・コンストラクタが準備作業を行うことに対して、デストラクタは後始末に用いることができる
・定義書式: ~クラス名(){…}
・コンストラクタとは異なり、引数は指定できない(よってオーバーロードも不可)
・戻り値はなく、voidを指定することもできない
・複数のオブジェクトが消された場合、デストラクタの実行順序は不定だが確実に実行される

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

・変数dt2、dt3を使用せず、変数dt1のみで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); //コンストラクタが呼ばれる①
        Console.WriteLine("dt1生成");
        dt1 = new DestructTest(2); //コンストラクタが呼ばれる②(これで①は不要になる)
        Console.WriteLine("dt1上書①");
        dt1 = new DestructTest(3); //コンストラクタが呼ばれる③(これで②も不要になる)
        Console.WriteLine("dt1上書②");
        Console.ReadLine(); //入力待ち
    } //この直後にデストラクタが3つ呼ばれる
}

今週の話題

ゲームソフト販売本数ランキング:今週1位も「ドンキーコング リターンズ HD(Switch)」 GO!
スクエニ、2025年第3四半期決算を発表。営業利益は4.4%減。『ドラクエ3リメイク』は当初の想定を上回る販売数に、スマホ・PCブラウザゲームは弱含み GO!
任天堂が今期業績予想を再度引き下げ、年末商戦でハード・ソフトの販売伸び悩む【ゲーム企業の決算を読む】GO!
ケイブ、4割の営業減益で上半期を折り返し―『メテオアリーナ』の償却費負担重く【ゲーム企業の決算を読む】GO!
スイッチ2「リスクをとりつつ需要を満たせる」供給体制に。「購入しやすい価格」も考慮―スイッチ向け新作も引き続き展開か? GO!

トランプ政権の新関税政策、米業界団体ESAがゲーム機器への打撃を懸念―半導体関税でコンソール価格上昇の可能性 GO!

前回のコメント

・ありがとうございました。
・今回もありがとうございました。
 次回もよろしくお願いします。
・今日もありがとうございました。次も頑張ります。

 応援します。

・クラスの話を聞くとプログラムの話が点がつながってくような感覚になっていって、楽しくなってきました。
 また来週もお願いします。

 何よりです。
 「グループ開発・部品化・再利用」のために何が必要かを的確に理解してください。