こんにちは。明月です。
この投稿はC#のインタフェース(interface)に関する説明です。
以前の投稿でインスタンスを生成する方法と継承に関して説明しました。
link - [C#] 11. インスタンスう生成(new)とメモリ割り当て(StackメモリとHeapメモリ)そしてヌル(null)
link - [C#] 13. クラスの継承と再定義(override)する方法、overrideとnewの差異
クラスの共通的な内容を抽象クラスで作成して継承しながらクラスを定義することに関して説明しました。
でも、C#では二つ以上の抽象クラスを継承することができません。
using System;
namespace Example
{
// ATypeAbstractClass抽象クラス
abstract class ATypeAbstractClass
{
// 抽象メソッド
public abstract string GetATypeName();
}
// BTypeAbstractClass抽象クラス
abstract class BTypeAbstractClass
{
// 抽象メソッド
public abstract string GetBTypeName();
}
// 二つの抽象クラスを継承する。
class Example : ATypeAbstractClass, BTypeAbstractClass
{
// ATypeAbstractClassの抽象クラスを再定義
public override string GetATypeName()
{
return "A";
}
// BTypeAbstractClassの抽象クラスを再定義
public override string GetBTypeName()
{
return "B";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("GetATypeName - " + GetATypeName());
Console.WriteLine("GetBTypeName - " + GetBTypeName());
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// インスタンス生成
Example ex = new Example();
// 出力関数
ex.Print();
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
エラーが発生します。理由としては、複数継承エラーです。
複数の継承でも上みたいに使うと問題がなさそうです。でも、Print関数がExampleのクラスではなく、抽象クラスにある関数なら。
継承するクラスではATypeAbstractClassのクラスの関数が使うかBTypeAbstractClassのクラスの関数が使うかを分からなくなります。
それでC#には複数の継承を禁止させています。
上の話はHeapメモリの中でも話です。
それならStackメモリに変数を宣言する時にはオブジェクトの特性上のオブジェクト別に片付ける必要がある時があります。
using System;
namespace Example
{
// IATypeInterfaceインタフェース
interface IATypeInterface
{
// メソッド定義
string GetATypeName();
void Print();
}
// IBTypeInterfaceインタフェース
interface IBTypeInterface
{
// メソッド定義
string GetBTypeName();
void Print();
}
// 二つのインタフェースを継承する。
class Example : IATypeInterface, IBTypeInterface
{
// IATypeInterfaceのインタフェースの関数を再定義
public string GetATypeName()
{
return "A Example";
}
// IBTypeInterfaceのインタフェースの関数を再定義
public string GetBTypeName()
{
return "B Example";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("Example - GetATypeName - " + GetATypeName());
Console.WriteLine("Example - GetBTypeName - " + GetBTypeName());
}
}
// IATypeInterfaceのインタフェースを継承する。
class AExample : IATypeInterface
{
// IATypeInterfaceのインタフェース関数を再定義
public string GetATypeName()
{
return "A - AExample";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("AExample - GetATypeName - " + GetATypeName());
}
}
// IBTypeInterfaceのインタフェースを継承する。
class BExample : IBTypeInterface
{
// IATypeInterfaceのインタフェース関数を再定義
public string GetBTypeName()
{
return "B - BExample";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("BExample - GetBTypeName - " + GetBTypeName());
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// インスタンス生成
Example ex = new Example();
// 出力関数
ex.Print();
// インスタンス生成
AExample ex1 = new AExample();
// 出力関数
ex1.Print();
BExample ex2 = new BExample();
// 出力関数
ex2.Print();
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
Exampleクラスを見ればIATypeInterfaceのインタフェースとIBTypeInterfaceのインタフェースを継承しました。
つまり、IATypeInterfaceのインタフェースの関数とIBTypeInterfaceのインタフェースの関数を再定義すべきです。
それで二つのインタフェースを継承したExampleクラスは二つのインタフェースの関数を再定義しました。
AExampleクラスの場合はIATypeInterfaceインタフェースを継承したので、IATypeInterfaceインタフェースの関数を再定義しました。
BExampleクラスの場合はIBTypeInterfaceインタフェースを継承したので、IBTypeInterfaceインタフェースの関数を再定義しました。
そしてMain関数でインスタンスを生成してPrint関数を呼び出ししました。
インタフェースは抽象クラスと違うのが中でメンバー変数と一般関数を実装することができません。ただ、定義だけします。そうなので、継承する関数では再定義(override)のキーワードを付けてありません。
こんなことを見れば、内部の動作実装やメモリの割り当てのメンバー変数の実装がなく、ただ定義だけあるのでなぜ必要か分からないですね。
しかし、Stackメモリにインスタンスのポインタ値を入れてHeapメモリに割り当てします。つまり、クラスの実体はHeapメモリにあり、それを我々はオブジェクト(Object)といいます。
簡単なプログラムはこのオブジェクトが何個しかないですが、大きいプログラムはこのオブジェクトがすごく多いです。我々はこのオブジェクトを役割や性質により分類する必要があります。
using System;
namespace Example
{
// IATypeInterfaceのインタフェース
interface IATypeInterface
{
// メソッド定義
string GetATypeName();
void Print();
}
// IBTypeInterfaceのインタフェース
interface IBTypeInterface
{
// メソッド定義
string GetBTypeName();
void Print();
}
// インタフェースを継承する。
class Example : IATypeInterface, IBTypeInterface
{
// IATypeInterfaceのインタフェースの関数を定義
public string GetATypeName()
{
return "A Example";
}
// IBTypeInterfaceのインタフェースの関数を定義
public string GetBTypeName()
{
return "B Example";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("Example - GetATypeName - " + GetATypeName());
Console.WriteLine("Example - GetBTypeName - " + GetBTypeName());
}
}
// IATypeInterfaceのインタフェースの関数を定義
class AExample : IATypeInterface
{
// IATypeInterfaceのインタフェースの関数を定義
public string GetATypeName()
{
return "A - AExample";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("AExample - GetATypeName - " + GetATypeName());
}
}
// IBTypeInterfaceのインタフェースの関数を定義
class BExample : IBTypeInterface
{
// IATypeInterfaceのインタフェースの関数を定義
public string GetBTypeName()
{
return "B - BExample";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("BExample - GetBTypeName - " + GetBTypeName());
}
}
class Program
{
// 実行関数
public static void Main(string[] args)
{
// インスタンスを生成
Example ex = new Example();
AExample ex1 = new AExample();
BExample ex2 = new BExample();
// IATypeInterfaceのインタフェースのグループ
IATypeInterface[] aTypes = new IATypeInterface[]
{
ex,ex1
};
// IBTypeInterfaceのインタフェースグループ
IBTypeInterface[] bTypes = new IBTypeInterface[]
{
ex,ex2
};
// IATypeInterfaceのインスタンスグループの出力
foreach (IATypeInterface a in aTypes)
{
a.Print();
}
// IBTypeInterfaceのインタフェースグループの出よく
foreach (IBTypeInterface b in bTypes)
{
b.Print();
}
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例みたいにインスタンスの三つを割り当てして各インタフェースグループにより分類してPrint関数を呼び出して出力しました。
using System;
namespace Example
{
// ITypeInterfaceのインタフェース
interface ITypeInterface
{
// メソッド定義
string GetTypeName();
void Print();
}
// ITypeInterfaceのインタフェースを継承する。
class AExample : ITypeInterface
{
// ITypeInterfaceのインタフェースの関数を定義
public string GetTypeName()
{
return "A - AExample";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("AExample - GetTypeName - " + GetTypeName());
}
}
// ITypeInterfaceのインタフェースを継承する。
class BExample : ITypeInterface
{
// ITypeInterfaceのインタフェースの関数を定義
public string GetTypeName()
{
return "B - BExample";
}
// 出力関数
public void Print()
{
// コンソール出力
Console.WriteLine("BExample - GetTypeName - " + GetTypeName());
}
}
class Program
{
// パラメータにより割り当てするクラスが違う。
public static ITypeInterface GetTypeClass(bool type)
{
// trueならAExampleクラスを割り当て
if (type)
{
return new AExample();
}
// falseならBExampleクラスを割り当て
else
{
return new BExample();
}
}
// 実行関数
public static void Main(string[] args)
{
// パラメータでtrueを渡したのでAExampleクラスのインスタンスが生成
ITypeInterface type = GetTypeClass(true);
// Print関数を実行
type.Print();
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
関数を利用してパラメータによりインスタンスの生成を別にすることができます。
GetTypeClass関数によりtrueの場合はAExampleクラスのインスタンスを生成するし、falseの場合はBExampleクラスのインスタンスを生成します。
このようにインタフェースは直接にインスタンスを生成することではないですが、生成されたインスタンスをインタフェースにより分類ができます。
そしてインタフェースはOOPのデザインパターン(プロジェクト設計)の基礎になります。
ここまでC#のインタフェース(interface)に関する説明でした。
ご不明なところや間違いところがあればコメントしてください。
- [C#] 22. インデクサー(indexer)を使う方法2019/07/13 01:06:04
- [C#] 21. C#のプロパティ(Property)2019/07/13 00:56:20
- [C#] 20. オブジェクト指向プログラミング(OOP)の4つの原則(カプセル化、抽象化、継承化、多相化(ポリモーフィズム))2019/07/12 00:17:35
- [C#] 19. 列挙型(enum)を使う方法2019/07/11 23:13:25
- [C#] 18. 構造体(Struct)、そして値型を参照するタイプ(Reference of value type)と参照型を参照するタイプ(Reference of reference type)2019/07/10 23:57:25
- [C#] 17. thisとbaseのキーワード2019/07/10 23:43:56
- [C#] 16. 継承禁止のキーワードのsealed2019/07/10 00:19:18
- [C#] 15. インタフェース(interface)2019/07/10 00:06:17
- [C#] 14. 抽象クラス(abstract)と抽象メソッド(abstract)、そして仮想関数(virtual)2019/07/08 23:04:09
- [C#] 13. クラスの継承と再定義(override)する方法、overrideとnewの差異2019/07/08 22:55:00
- [C#] 12. Staticとアクセス修飾子、そしてカプセル化2019/07/07 23:12:30
- [C#] 11. インスタンスう生成(new)とメモリ割り当て(StackメモリとHeapメモリ)そしてヌル(null)2019/07/07 22:54:13
- [C#] 10. クラスを作成する方法(コンストラクタ、デストラクタ)2019/07/06 00:53:17
- [C#] 9. 関数(Method)とオーバーロード、再帰呼び出し2019/07/06 00:38:29
- [C#] 8. 配列とリスト2019/07/05 00:12:42
- check2024/04/10 19:03:53
- [Java] 64.Spring bootとReactを連結する方法(Buildする方法)2022/03/25 21:02:18
- [Javascript] Node.jsをインストールしてReactを使う方法2022/03/23 18:01:34
- [Java] 63. Spring bootでcronスケジューラとComponentアノテーション2022/03/16 18:57:30
- [Java] 62. Spring bootでWeb-Filterを設定する方法(Spring Security)2022/03/15 22:16:37
- [Java] JWT(Json Web Token)を発行、確認する方法2022/03/14 19:12:58
- [Java] 61. Spring bootでRedisデータベースを利用してセッションクラスタリング設定する方法2022/03/01 18:20:52
- [Java] 60. Spring bootでApacheの連結とロードバランシングを設定する方法2022/02/28 18:45:48
- [Java] 59. Spring bootのJPAでEntityManagerを使い方2022/02/25 18:27:48
- [Java] 58. EclipseでSpring bootのJPAを設定する方法2022/02/23 18:11:10
- [Java] 57. EclipseでSpring bootを設定する方法2022/02/22 19:04:49
- [Python] Redisデータベースに接続して使い方2022/02/21 18:23:49
- [Java] Redisデータベースを接続して使い方(Jedisライブラリ)2022/02/16 18:13:17
- [C#] Redisのデータベースを接続して使い方2022/02/15 18:46:09
- [CentOS] Redisデータベースをインストールする方法とコマンドを使い方2022/02/14 18:33:07