ラベル inheritance の投稿を表示しています。 すべての投稿を表示
ラベル inheritance の投稿を表示しています。 すべての投稿を表示

2018年2月20日火曜日

クラス、そして継承の話

今回はクラスの話になります。

C#はC++とJavaを源流とする言語なんだそうです。ということは、オブジェクト指向であり、クラスという概念を避けて通れません。特にC#では、前回のエントリーにも書いたように、全ての手続きはクラスに属さなければならない決まりになっているので、プログラムを書く=クラスを定義する、ということになります。マイクロソフトのこのドキュメントの二つ目のパラグラフに書いてありますね。

クラス


次のリストは、私がクラスの定義の学習をしたときに使ったプログラムです。

using System;

namespace sample5
{
    class Program
    {
        static void Main(string[] args)
        {
            MyObject obj = new MyObject();
            obj.name = "Gustav";
            obj.age = 56;
            obj.printData();
            Console.ReadKey();
        }
    }

    class MyObject
    {
        public string name = "(noname)";
        public int age = 0;
        public void printData()
        {
            Console.WriteLine("名前 : {0}, 年齢 : {1}歳",name, age);
        }
    }
}
この中では、sample5という名前空間(クラスを整理する為の棚のようなもの)の中に、ProgramというクラスとMyObjectというクラスが定義されています。ProgramクラスにはMainメソッドがありますね。OS上の各種セットアップ処理が終わった後に、プログラム本体の入口としてここに制御が移ります。

下にあるMyObjectクラスの定義では、メンバーの変数やメソッドの定義がなされます。ここで、各メンバーにはpublic宣言がなされているので、MyObjectクラスの外からこれらメンバーを読んだり書いたり呼び出したりできますが、private宣言というものもあり、private宣言がなされたメンバーは、クラスの外からはアクセスできません。

Mainメソッドの1行目で、

MyObject obj = new MyObject();

という記述がされています。

実は、C#ではstatic宣言がされているクラスを除いて、クラスはnew演算子を使って実態を作る(インスタンスを作る)操作をしないと、使うことが出来ません。クラスの宣言は文字通り宣言だけで、実態を作ることで初めて使うことができる、ということになっています。

C++では、new演算子を使うインスタンス生成と使わないインスタンス生成がありますが、C#では、クラスのインスタンス生成には必ずnew演算子を使う決まりになっています。

なお、C++におけるインスタンス生成で、new 演算子を使った場合はオブジェクトがヒープ領域に、使わない場合はスタック領域に生成され、new演算を使わない場合は、スコープから抜けるとオブジェクトは開放されてしまいます。

クラスの継承


既存のクラスの性質を受け継いで、新たな機能を追加したクラスを作ることを継承と言います。派生と言うこともあるようです。このサイト様もよく参考にさせていただいていますけど、ここに詳しい説明があります。

この概念、個人で小規模なプログラミングをやってる人間にはあまりありがたみが分からないのですが、チームで仕様書ベースで開発するようなケースでは有用なのでしょう。また、あらかじめ用意されている、たとえば.NETの環境で、ライブラリーを継承して新たにクラスを作る、なんてときには嬉しい機能なのだと今回の学習で思いました。

なお、継承元のクラスを基底クラス、又はスーパークラス、継承を受ける側を派生クラス、又はサブクラスと呼びます。

次のリストでは、クラスの継承をしています。MyObjectクラスの定義があり、その次にEnchancedMyObjectクラスの定義がありますが、

class EnhancedMyObject : MyObject

の、": MyObject"の記述が、MyObjectクラスを継承することを示しています。

using System;

namespace sample6
{
    class Program
    {
        static void Main(string[] args)
        {
            EnhancedMyObject obj = new EnhancedMyObject();
            obj.name = "Gustav";
            obj.age = 56;
            obj.mail = "mail@truth-maker.com";
            obj.printData();
            obj.printDataEnchanced();
            Console.ReadKey();
        }
    }

    class MyObject
    {
        public string name = "(noname)";
        public int age = 0;
        public void printData()
        {
            Console.WriteLine("名前 : {0}, 年齢 : {1}歳",name, age);
        }
    }

    class EnhancedMyObject : MyObject 
    {
        public string mail = "(no mail)";

        public void printDataEnchanced()
        {
            Console.WriteLine("名前 : {0}\n\t 年齢 : {1}歳\n\t メール : {2}.", name, age, mail );
        }
    }   
}   

Mainメソッドの中で、EnhancedMyObject型のオブジェクトをnew演算子で生成しています。そして、obj.printData()メソッドとobj.printDataEnhanced()メソッドを呼び出しています。

obj.printData()メソッドは、基底クラスに存在しているメソッドなので、派生クラスにも引き継がれ、派生クラスでも使うことが出来ます。プログラムを実行すると、下記のような結果になります。

1行目でソースのコンパイル、2行目で実行させています。

MacBook-Pro:sample6 gustav$ mcs Program.cs
MacBook-Pro:sample6 gustav$ mono Program.exe
名前 : Gustav, 年齢 : 56歳
名前 : Gustav
         年齢 : 56歳
         メール : mail@truth-maker.com.

まず最初に基底クラスから引き継がれたのprintData()メソッドが実行され、次に派生クラスで追加したprintDataEnhanced()メソッドが実行されていますね。

今回はクラスと継承のお話でした。今回はここまで。