10_継承 インターフェイス


もう少しでWindowsらしいプログラムが作れます。
がんばろう。
コンストラクタとかプロパティとかメソッドとか引数とかちゃんと覚えてないとこれからイミフになってきますよ。こういうのは復習が大事。

継承

using System;
class Vehicle{
    public int fuel,teiin;   //都合によりpublicにしています

    public void Show(){
        Console.WriteLine("fuel:" + fuel + " teiin:" + teiin);
    }
}

class Car : Vehicle{    //CarはVehicleを継承してます
    string num;    //車のナンバー

    public Car(int f, int t, string n){//コンストラクタ
        fuel = f;    //継承により、fuelとteiinが使えます
        teiin = t;
        num=n;
    }

    public void NumShow(){
        Console.WriteLine("num:" + num);
    }
}

class Test12{
    static void Main(){
        Car car = new Car(398, 9, "3535-6");   //さくや、みこみこ
        car.Show();    //継承したので、Showが使えます。
        car.NumShow();
    }
}

クラスの名前のあとに :(コロン)をつけると継承ができます。
継承すると、public/protectedのメンバを全部うけつぎます。

protectedはpublicとprivateの中間のようなアクセス修飾子で
継承しているクラスからはアクセス可能でそれ以外からは不可能!

同じようなクラスを大量に作ったとしましょう。
もし継承を使わなかったらいちいちコピペしなければならないかも。そうしたら、バグがあったりしたらコピペしたすべてのクラスに手を加えなきゃならないし不便です。でも継承したのなら基本クラスだけ手を加えればいいので楽です。いちいち宣言しなくても良いので入力の手間もかからないし。
動画では基本クラス、派生クラスと呼んでますが
「親クラス、子クラス」「スーパークラス、サブクラス」「基底クラス、派生クラス」等と言うこともあります。
このWikiでは親、子を使います。
まぁどんな呼び方でも言いたいことはわかるでしょう。

また、コンストラクタについては、自動的に親クラスの引数なしの
コンストラクタを実行します。親クラスに引数なしのコンストラクタがなかったら、ちゃんとコンストラクタを設定しないとエラーになります。
using System;
class Oya{
    public Oya(){
        Console.WriteLine("親コンストラクタ呼び出し");
    }
}
class Ko : Oya{
    public Ko(){
        Console.WriteLine("子コンストラクタ呼び出し");
    }
}
class MainClass{
    static void Main(){
        Ko ko = new Ko();    //親コンストと子コンストの両方
    }                        //表示されます
}

親クラスが複数のコンストラクタを持っていた場合
子のコンストラクタの後にbaseとつけるとできます。
using System;
class Oya{
    public Oya(int x){
        //なんか適当に書いてください
    }
    public Oya(string s){
        //なんか適当なのを書いてください
    }
}
class Ko : Oya{
    public Ko() : base(10){    //10はintなのでOya(int)を呼び出します
        Console.WriteLine("子コンストラクタ呼び出し");
    }
}
class MainClass{
    static void Main(){
        Ko ko = new Ko();    //baseで指定した親コンストと子コンストの両方
    }                        //表示されます
}
コンストラクタやbase()の部分を変えて
いろいろやってみてください。


objectクラス

C#には(.netFrameworkクラスライブラリには)objectクラスってのがあります。
これはすべての基底クラスです。つまりすべての型は何も継承しなくてもobjectクラスだけは勝手に引き継ぎます。(実はポインタ型というのが引き継がないが知らなくて良いです)
たとえばobjectクラスはToStringメソッドがあります。このためどんな型だろうがToStringを持っています。

using System;
class MyClass    //一見何もないクラス
{
}

class MainClass{
    static void Main(){
        MyClass mc = new MyClass();
        string s=mc.ToString();    //勝手にToStringが追加されてる
        Console.WriteLine(s);     //mcはMyClass
    }
}

MyClass と表示されたと思います。ToStringは普通はクラス名を表示します。しかしオーバーライドを利用すればintやDateTimeのようにToStringを独自に設定することもできます。たとえば
int x=10; x.ToString()← "10"
DateTime dt =DateTime.Now; dt.ToString()←"年/月/日 時間/分/秒"

ダメな継承例

class Oya : Ko{    //Koをひきつぐ
public int x;
}
class Ko : Oya{    //さらにOyaをひきつぐ
}
こんなのがダメなのは説明するまでもない。。。

class A{
}
class B{
}
class C : A,B{    //C#ではクラスからの継承は一個だけです
}                 //二つ継承しようとするとエラー

class Oya{
    int x;
}
class Ko : Oya{
    Setx(){
        x=10;      //Oyaのxはprivateなのに注意
    }
}

class Oya{
    public Oya(string s){    //コンストラクタ
        Console.WriteLine(s);
    }
}
class Ko : Oya{
    public Ko(){    //baseを指定していないので勝手にOya()を呼び出そうとするけれど
        Console.WriteLine("子");     //Oya()は存在しないエラー
    }
}

class Oya{
}
class Ko : Oya {
    public void func(){
    //何かする
    }
}
//main部分
Oya oya = new Oya();
oya.func();     //子は親を継承してるが、親は子を継承していないのでfuncは無い

class Oya{
    public void Show(){
    //何かの処理
    }
}

class Ko : Oya{
    public void Show(){    //Showメソッドの名前が重複しています
    //別の処理
    }
}
これはエラーにはなりませんが、「同じ名前のメソッドもってるぞ!newキーワードつけれ」みたいな警告が出されます。
(警告ってのは実行不可能ではないがミスである可能性が高いような
危険なことです)

new および overrideについて。

今まではKo ko = new Ko();
みたいにクラスとコンストラクタが同じでした。
まったく異なる型を代入しようとすると(暗黙変換を除いて)エラーがでます。
ですが継承関係のクラスなら型が違っても大丈夫。
Oya oya = new Ko();
もしくは
Ko ko = new Ko();
Oya oya = ko;
親クラスの変数は子クラスになれます
逆に、Ko ko = new Oya();
のように、子クラスは親クラスになることはできません。
java知ってる人はこの辺のオーバーライド等
関して、C#とは機能がまったく違う部分があるので要注意。

new Ko()で作られたのはKoクラスのインスタンスです。
それをOya型の変数に突っ込んでます。
さてOya oya = ko;の後はoyaは型どうなってるか?
Oya型で宣言して、ko型のインスタンスを代入されている。。。
実はoyaはOya型でもあり、Ko型でもあります。
静的な型がOya、動的な型がKo、と言います。

using System;
class Oya{
    public void Show(){
    //何かの処理
    }
}

class Ko : Oya{
    public void Show(){
    //別の処理
    }
}
static void Main(){
    Oya oya = new Ko();
    oya.Show();      //OyaクラスのShowが呼ばれる
}


何も書かなかったらOyaクラスのShowが実行されます。
でも警告「newをつけてください」って出てきます
KoクラスのShowにnewをつけてあげましょう。
public new void Show();   //new publicでもどっちでもいいです。
こうすれば、oya.Show()はOyaクラスのShowを実行してくれます。
しかし、Oyaクラスのメソッドにvirtual、子クラスのメソッドに
overrideをつけるとoya.Show()がKoクラスのShow()を実行します。

using System;
class Oya{
    virtual public void Show(){    //public virtualもOK
    //何かの処理
    }
}

class Ko : Oya{
    override public void Show(){   //public overrideもOK
    //別の処理
    }
}
static void Main(){
    Oya oya = new Ko();     //oyaは動的な型がKoなのでKoクラスのShow()
    oya.Show();            //を実行します。
}

newつけるのとoverrideつけるのは動作が逆になって紛らわしいですが
普通はバーチャル~オーバーライドのほうを使います。

継承は単に親クラスの持ってるものを引き継ぐという機能でなく
Oya oya = new Ko();みたいに型が異なった変数になることもできます。

インターフェイス

using System;
interface Itire{   //タイヤインターフェース、名前の最初にI
    void ShowTire();
    string Number {get;}    //プロパティも可能
}

class Car : Itire{
    string num;
    int tire = 4;

    public Car(String n){
        num = n;
    }

    public void ShowTire(){    //インターフェイスの実装
        Console.WriteLine("tireの数は"+tire+"です");
    }

    public string Number{    //プロパティも実装
        get{
            return num;
        }
    }
}

class Test12
{
    static void Main()
    {
        Car car = new Car("3535-06");
        car.ShowTire();
        Console.WriteLine("ナンバー:" + car.Number);
    }
}

インターフェイスの名前には最初に大文字のI(アイ)をつけるのがスタンダードです。メソッドとプロパティ(やってませんがインデクサ、イベントも)をメンバにできますがフィールド(変数)は無理。
Javaとは違います。さらに勝手にpublicになります。だから実装側でもpublicにしないといけません。

ダメなインターフェイスの例
interface Interface1{
    int x;    //ただの変数は×(プロパティOK)
    private void func();    //勝手にpublicになるのでprivate×
    public void func2();    //勝手にpubになるので二重宣言になる×
    void func3(){           //インターフェイスの中でメソッドとか定義するのは×
    //処理
    }
}
インターフェイスは通常クラスの継承と違って多重に実装可能です。
複数実装するときはコンマで区切ります
class MyClass : Interface1, Interface2  //こんな書き方をします
インターフェイスはインスタンスを作成できません(newできません)が
変数を宣言することはできます。
Interface1 sample; //OK
Interface1 sample = new Interface1(); //NG

overrideでやったのとまったく同じように、インターフェイスも子クラスを代入できます
using System;
interface IMyInterface{
    void Show();
}

class Implement1 : IMyInterface{    //Implementは実装
    public void Show(){
        Console.WriteLine("実装1です");
    }
}

class Implement2 : IMyInterface{
    public void Show(){
        Console.WriteLine("実装2です");
    }
}

class MainClass{
    static void Main(){
        IMyInterface mi = new Implement1();    //miの型に注意
        mi.Show();    //miはImplement1なのでImplement1のShow
        mi = new Implement2();
        mi.Show();    //こっちはImplement2のShow
    }
}


インターフェイスってどんな時に使うのか
たとえばですが
string型とint型はIcomparable(T)インターフェイスを実装してます。
int32のほうとstringのほうのページで小さく
実装
IComparable<(Of <(T>)>).CompareTo(T)
と書いてるのがわかります。
(T)ってのはあまり関係ないので飛ばしますが「比較可能」であるインターフェースです。intは2と4は4のほうが大きいとかすぐわかりますが、文字で比較ってのは、辞書順にならべて比較します。
abcdeとzyならzyのほうが大きいです(辞書は、aのほうが最初)
この「辞書順に比較する」「数値が大きいほうを比較する」ってのはまったく異なった方法ですけどComperToって同じ名前で実装してます。
(T)ってのはジェネリックという機能です。でもここでは説明しません。

最後に関係ない話
Visual Studioの便利な使い方。
Visual Studioは大変便利な機能があります。
ちょっとだけ紹介します。

ブックマーク
コードの行に「ブックマーク」を設定すると、ショートカットキーで
その行に飛べます。CTRLキー+B、Tで設定ができます。
ブックマークに設定した行にはCTRL+B、P or Nで移動できます。
もちろん、キーボードの設定を変えていなければですが。
キーボードの設定は、メニュー(ファイルとか編集とか表示とかある一番上のやつ)のツール→オプション→環境→キーボード
で、「以下の文字列を~~表示」ってのでブックマークなどと入力したら出てきます。

インデントが汚れたコードの掃除
http://www21.atwiki.jp/cmatome?cmd=upload&act=open&pageid=23&file=Visual+Stdio.jpg
これはわざとインデント(空白)をずらしまくってますが
コピーペーストとかしまくるとたまにずれてきます。
こんなときは
CTRL+Aで全選択、CTRL+Xで切り取り、CTRL+Vで貼り付け
をしてやるとすべてきれいになります。

テンプレート
一番最初に書かれるやつ。
C#のコード作るときいちいち
using System;だのMainだの書いてたら超面倒なので
最初のコードをテンプレートとして設定できます。
デフォルトに入ってるWindows フォームとかでもいいですが
自分専用のテンプレートを作るには
メニューのファイル→テンプレートのエクスポート
でできます。

ショートカットキー
CTRL+Sで上書き保存、CTRL+Aで全選択
みたいなやつ。覚えておくと便利なので使えそうなのを覚えよう。
Visual StudioだとCTRL+Xキーが
何も選択していないときは行まるごと切り取り
してくれるので超便利です。
http://msdn.microsoft.com/ja-jp/vstudio/dd183140.aspx

他にも便利な機能がいっぱいあるんで利用しよう。

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2009年11月30日 20:56