[C#] 14. 抽象クラス(abstract)と抽象メソッド(abstract)、そして仮想関数(virtual)
こんにちは。明月です。
この投稿はC#で使う抽象クラス(abstract)と抽象メソッド(abstract)、そして仮想関数(virtual)に関する説明です。
以前の投稿でクラスの継承、再定義する方法に関して説明したことがあります。
link - [C#] 13. クラスの継承と再定義(override)する方法、overrideとnewの差異
クラスの継承は基本的にクラスの機能をそのままに引き続きに継承して新しくクラスを拡張、修正する概念だと説明しました。そのところで、親クラスは継承する前にもインスタンスを生成して使えますが、今回はクラス自体は使えない不完全なクラスでただ継承して再定義してから使うクラスを紹介します。
つまり、クラス自体をインスタンス生成が不可能で継承して再定義して使えるという意味です。
using System;
namespace Example
{
// 抽象クラス生成
abstract class AbstractExample
{
// 出力関数
public void Print()
{
// コンソール出力 - GetData関数を呼び出す。
Console.WriteLine("GetData function - " + GetData());
}
// GetData関数はこのクラスで定義せずに継承するクラスで強制再定義を指定する。
protected abstract string GetData();
}
// 抽象クラスを継承
class Example : AbstractExample
{
// 抽象クラスからGetData関数が完全に実装されてないので、継承するクラスで必ず再定義すべき。
protected override string GetData()
{
// String返却
return "Hello world";
}
}
class Program
{
// 実行関数
static void Main(string[] args)
{
// Exampleクラスのインスタンス生成
Example ex = new Example();
// Print関数を呼び出す。
ex.Print();
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例をみればAbstractExampleクラスのGetData関数は宣言だけして内容は実装してないです。
そしてクラスと関数の前にabstractのキーワードを使いました。それならAbstractExampleクラスは抽象クラスになり、GetDataは抽象メソッドになります。
つまり、抽象クラスは未完成クラスで抽象クラス自体はインスタンス生成ができなくて、必ず継承してから使えます。
また、抽象メソッドは継承するクラスで必ず再定義(override)すべきになります。
なので、Exampleクラスで抽象クラスのAbstractExampleクラスを継承する時に抽象メソッドを再定義(override)しました。
この抽象クラスを使う目的は多いクラスの共通部分を一つに取り縛って共通クラスとして実装する時によく使います。
using System;
namespace Example
{
// 抽象クラス生成
abstract class AbstractExample
{
// 出力関数
public void Print()
{
// コンソール出力 - GetData関数を呼び出す。
Console.WriteLine("GetData function - " + GetData());
}
// GetData関数はこのクラスで定義せずに継承するクラスで強制再定義を指定する。
protected abstract string GetData();
}
// 抽象クラスを継承
class Example1 : AbstractExample
{
// 抽象クラスからGetData関数が完全に実装されてないので、継承するクラスで必ず再定義すべき。
protected override string GetData()
{
// String返却
return "Example1";
}
}
// 抽象クラスを継承
class Example2 : AbstractExample
{
// 抽象クラスからGetData関数が完全に実装されてないので、継承するクラスで必ず再定義すべき。
protected override string GetData()
{
// String返却
return "Example2";
}
}
class Program
{
// 実行関数
static void Main(string[] args)
{
// 抽象クラスの指示子で配列を宣言
AbstractExample[] array = new AbstractExample[]
{
// Example1クラスのインスタンス生成
new Example1(),
// Example2クラスのインスタンス生成
new Example2()
};
// インスタンスを繰り返しで出力
foreach (AbstractExample ex in array)
{
// 指示子はAbstractExample(Stack)だが、HeapにはExample1あるいはExample2のクラスのインスタンスが割り当てしている。
ex.Print();
}
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上のMain関数で指示子は抽象クラスでインスタンス生成して割り当てするのは継承したクラスです。
その関係に関しては以前の投稿で説明したことがあるのでご参考してください。
link - [C#] 11. インスタンスう生成(new)とメモリ割り当て(StackメモリとHeapメモリ)そしてヌル(null)
またMain関数をみるとforeachでPrint関数を呼び出します。
指示子の抽象クラスには実装はしてないですが、Print関数が宣言されています。なので、Print関数を呼び出して各インスタンスの関数を呼び出すことができます。
結果はPrint関数の文言と各インスタンスで再定義した関数GetDataの結果がコンソールに出力されます。
abstarctクラスで関数が実装されていますが、virtualキーワードを使って再定義ができるような関数指定も可能です。
using System;
namespace Example
{
// 抽象クラス生成
abstract class AbstractExample
{
// 出力関数
public void Print()
{
/// コンソール出力 - GetData関数を呼び出す。
Console.WriteLine("GetData function - " + GetData());
}
// virtualは仮想関数、抽象関数と違い、実装が可能。
protected virtual string GetData()
{
return "AbstractExample";
}
}
// 抽象クラスを継承
class Example1 : AbstractExample
{
// 抽象クラスからGetData関数が再定義可能。
protected override string GetData()
{
// String返却
return "Example1";
}
}
// 抽象クラスを継承
class Example2 : AbstractExample
{
// 仮想関数は必ず再定義する必要がない。
}
class Program
{
// 実行関数
static void Main(string[] args)
{
// 抽象クラスの指示子で配列を宣言
AbstractExample[] array = new AbstractExample[]
{
// Example1クラスのインスタンス生成
new Example1(),
// Example2クラスのインスタンス生成
new Example2()
};
// インスタンスを繰り返しで出力
foreach (AbstractExample ex in array)
{
// 指示子はAbstractExample(Stack)だが、HeapにはExample1あるいはExample2のクラスのインスタンスが割り当てしている。
ex.Print();
}
// 任意のキーを押してください
Console.WriteLine("Press any key...");
Console.ReadLine();
}
}
}
上の例はvirtualキーワードを使って実装された関数を再定義できるように設定しました。
Example1クラスでは再定義して結果が再定義したGetData関数の結果が出力されます。
でもExample2クラスの場合は再定義してないですが、そうするとAbstractExampleクラスのGetData関数の結果が出力されますね。
ここまでC#で使う抽象クラス(abstract)と抽象メソッド(abstract)、そして仮想関数(virtual)に関する説明でした。
ご不明なところや間違いところがあればコメントしてください。
- [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
- [C#] 7. 制御文2019/07/05 00:05:30
- 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