講義メモ

・p.243「クラスの継承とコンストラクタ」から

p.243 クラスの継承とコンストラクタ

・どのクラスにおいても、コンストラクタを記述しないと、自動的に引数のないコンストラクタが用意される
・これは派生クラスでも同様
・しかし、派生クラスのコンストラクタの前には自動的に基本クラスのコンストラクタが実行される
・これにより、基本クラスから継承したデータメンバの初期化を基本クラスのコンストラクタに任させることができる
・基本クラスに引数を持つコンストラクタがあり、派生クラスにも引数を持つコンストラクタがある場合、引数を受け渡す必要があるので、baseキーワードを用いる
・書式: public 派生クラス名(型 引数,…) : base (受け取りたい引数,…) {…}

p.243 inheritance06.cs

//p.243 inheritance06.cs
using System;
class MyBase { //基本クラス
    protected int x;
    public MyBase() { //コンストラクタ(引数なし)
        Console.WriteLine("ここはMyBase");
        x = 10; //データメンバの初期化
    }
}
class Derived1 : MyBase { //派生クラス
    //ここに「protected int x;」があるとみなされる
    public Derived1() { //コンストラクタ(引数なし)
        //ここでMyBaseのコンストラクタを実行
        Console.WriteLine("ここはDerived1");
        x = 20; //データメンバの初期化
    }
}
class Derived2 : Derived1 { //派生の派生クラス
    //ここに「protected int x;」があるとみなされる
    public Derived2() { //コンストラクタ(引数なし)
        //ここでDerived1のコンストラクタを実行(中で)
        Console.WriteLine("ここはDerived2");
        x = 30; //データメンバの初期化
    }
    public void show() { //独自のメソッド
        Console.WriteLine("x = {0}", x);
    }
}
class inheritance06 {
    public static void Main() {
        Derived2 d2 = new Derived2(); //派生の派生クラスのコンストラクタを実行(3つのコンストラクタが動作)
        d2.show(); //x = 30
    }
}

p.245 inheritance07.cs

//p.245 inheritance07.cs
using System;
class MyBase { //基本クラス
    protected double d;
    public MyBase(double a, double b, double c) { //コンストラクタ(引数あり)   
        d = Math.Pow(b, 2.0) - 4.0 * a * c; //データメンバの初期化
    }
}
class MyJudge : MyBase { //派生クラス
    public bool bJudge;
    public MyJudge(double p, double q, double r) //コンストラクタ(引数あり) 
        : base(p, q, r) { //MyBaseクラスのコンストラクタに引数を渡す(p→a,q→b,r→c)
        //ここに「protected double d;」があるとみなされる
        //ここでMyBaseのコンストラクタ(p, q, r)を実行
        //つまり、ここに d = Math.Pow(q, 2.0) - 4.0 * p * r; があるとみなされる
        Console.WriteLine("判別式 = {0}", d);
        if (d < 0.0)
            bJudge = false;
        else
            bJudge = true;
    }
}
class inheritance07 {
    public static void Main() {
        MyJudge mj = new MyJudge(1.0, 2.0, 3.0);
        Console.WriteLine(mj.bJudge);
        MyJudge mk = new MyJudge(1.0, 4.0, 0.0);
        Console.WriteLine(mk.bJudge);
    }
}

p.247 抽象クラス

・継承を用いてクラスの上下関係を構築しておくと、具体的な記述は派生クラス側になり、基本クラスはクラス群を代表する存在になっていく
・例: 基本クラスはMonster、派生クラスはSlime、Dragon、その派生クラスはHoimiSlime など
・そして、基本クラスには具体的な記述をせず、派生クラスに任せる方が効率的な構造になる
・この時に用いる「中身は派生クラスで」というメソッドが抽象メソッド
・書式: abstruct 戻り値型 メソッド名(引数型 引数,…); //抽象メソッドは{}がなく;で閉じる
・抽象メソッドを持つクラスを抽象クラスといい、クラス名の前にもabstructを付記する
・書式: abstruct class クラス名 {…}
・抽象クラスはインスタンスを生成できない
・基本クラスが抽象クラスの場合、派生クラスでは全ての抽象メソッドをオーバーライドする必要がある
・あるいは、一部または全部の抽象メソッドをオーバーライドしないことで、派生クラスを抽象クラスにできる
・例: 基本クラスはMonster(抽象)、派生クラスはSkyMonster(抽象)、その派生クラスはDragonなど

p.248 abstract01.cs

//p.248 abstract01.cs
using System;
abstract class MyAb { //抽象クラス
    public abstract double Hanbetsu(double a, double b, double c); //抽象メソッド
}
class MyHanbetsu : MyAb { //派生クラス
    public override double Hanbetsu(double a, double b, double c) { //抽象メソッドのオーバーライド
        return Math.Pow(b, 2.0) - 4.0 * a * c;
    }
}
class abstract01 {
    public static void Main() {
        MyHanbetsu h = new MyHanbetsu(); //派生クラスのインスタンスを生成
        double d = h.Hanbetsu(1.0, 2.0, 3.0); //オーバーライドしたメソッドを実行
        Console.WriteLine(d);
    }
}

p.249 sealedクラス

・継承により基本クラスのメンバが引き継がれてしまうことを避けたい場合、sealedクラスにすれば良い
・書式: sealed class クラス名 {…}
・なお、C#が提供するクラスの中にも、sealedクラスが含まれている

p.250 クラスを分割定義する

・1クラスを複数のソースリストで記述できる
・これにより、ソースの長大化を防いだり、チーム開発を効率化できる
・テキストではクラス定義を2分割して1ソースに置いているが、通常、ソースの分割に用いる
・クラスを分割定義するには、classの前に partial を付記する(これを部分クラスともいう)
・部分クラスのどこかで定義したメンバは、他のソースにある部分クラスからも利用可能

アレンジ演習:p.250 partial01.cs

・018行目までをpartial01.csに、020行目以降をpartial01a.csに分離しよう
・なお、「using System;」は両方またはどちらか片方で必要に応じて配置すること

作成例 partial01.cs

//アレンジ演習:p.250 partial01.cs
using System;
partial class MyClass { //部分クラス
    public int x;
}
class partial01 { //通常のクラス
    public static void Main() {
        MyClass mc = new MyClass(); //部分クラスを利用可能
        mc.x = 10; //部分クラスにあるデータメンバ
        mc.Show(); //部分クラスの続きにあるメソッド
    }
}

作成例 partial01a.cs

//アレンジ演習:p.250 partial01a.cs
using System;
partial class MyClass { //部分クラスの続き
    public void Show() { //メソッドはこちらへ
        Console.WriteLine("x = {0}", x); //他の部分クラスにあるデータメンバを利用可
    }
}

p.251 メソッドを分割定義する

・分割したクラスにおいて、メソッドの定義とメソッドの内容を別々の部分クラスに記述できる
・これを部分メソッドという
・ただし、戻り値型がvoidで、privateなメソッドに限る
※ この仕掛は未完成のメソッドがある場合に便利で、 シグニチャだけを部分メソッドとして記述しておくと良い
※ 1メソッドを複数ソースファイルで記述できるわけではない

p.251 partialmethod01.cs

//p.251 partialmethod01.cs
using System;
partial class Partialmethod01 { //部分クラス①
  public static void Main() {
    Console.WriteLine("Mainメソッドです");
    Partialmethod01 pm = new Partialmethod01();
    pm.Func1(); //部分メソッド①を呼べる
    pm.Func2("テスト"); //部分メソッド②を呼べる
  }
  //ここではメソッドの中身を記述していない
  //戻り値はvoid型、privateでなくてはだめ
  partial void Func1(); //部分メソッド①の宣言のみ
  partial void Func2(string s); //部分メソッド②の宣言のみ
}
partial class Partialmethod01 { //部分クラス②
  partial void Func1(){ //部分メソッド①の内容を記述
    Console.WriteLine("パーシャルメソッド1です");
  }
}
partial class Partialmethod01 { //部分クラス③
  partial void Func2(string s) { //部分メソッド②の内容を記述
    Console.WriteLine("引数は「{0}」です", s);
  }
}

p.254 練習問題1,2:ヒント

・p.231 override01.csをベースにすると良い
・Mainメソッドの作例:
  A2 a2 = new A2(); //派生クラスのインスタンスを生成
  Console.WriteLine(a2.Calc(5, 8)); //差を表示?
  A1 a1 = a2; //基本クラス型の変数にインスタンスを代入
  Console.WriteLine(a1.Calc(5, 8)); //和を表示? 差を表示?

コメントを残す

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