C#の抽象クラスと抽象メソッドとは?実装例を交えてやさしく解説
生徒
「クラスの仕組みは少し分かってきたのですが、抽象クラスって何ですか?」
先生
「抽象クラスとは、"共通のルールだけを決めるための設計図"のようなクラスのことです。」
生徒
「設計図だけってことは、実際には使えないんですか?」
先生
「そのとおりです。抽象クラスだけではオブジェクトは作れません。使うには、子クラスで具体的な中身を作る必要があります。」
生徒
「なるほど!では、抽象メソッドって何ですか?」
先生
「抽象メソッドは、抽象クラスの中で定義される、“中身がないメソッド”のことです。子クラスで中身を必ず作る決まりがあります。」
1. 抽象クラスとは?
C#の抽象クラス(abstract class)は、共通する性質や動作のルールだけを決めて、実際の中身は子クラスに任せるための土台です。
たとえば、「動物」という抽象的な考え方があったとき、そこに「鳴く」や「動く」といった共通の機能を定義し、それぞれの動物(犬・猫など)がそれをどう実行するかを自分で決めるイメージです。
ポイント:
- abstract修飾子をクラスにつける
- 抽象クラスからは直接インスタンス(new)を作れない
- 共通の処理や変数は書ける
2. 抽象メソッドとは?
抽象メソッド(abstract method)は、メソッドの名前と引数だけを決めて、中身(処理の内容)は書かない関数のことです。
このメソッドを抽象クラスの中に書いておくことで、子クラスは「必ずこのメソッドを自分で作ってね!」という約束になります。
書き方のポイント:
- abstractキーワードを使う
- 中括弧 {} を使わずに、セミコロン ; で終わる
- 抽象クラスの中でしか使えない
3. 抽象クラスと抽象メソッドのサンプルコード
では、実際にC#で抽象クラスと抽象メソッドを使ったサンプルを見てみましょう。
using System;
// 抽象クラス
abstract class Animal
{
// 抽象メソッド(中身は書かない)
public abstract void Speak();
// 共通メソッド(中身はある)
public void Eat()
{
Console.WriteLine("エサを食べます。");
}
}
// 子クラス:Dog(Animalを継承)
class Dog : Animal
{
// 抽象メソッドの中身を定義
public override void Speak()
{
Console.WriteLine("ワンワン!");
}
}
// 子クラス:Cat(Animalを継承)
class Cat : Animal
{
// 抽象メソッドの中身を定義
public override void Speak()
{
Console.WriteLine("ニャーニャー!");
}
}
class Program
{
static void Main()
{
Animal dog = new Dog();
dog.Speak(); // ワンワン!
dog.Eat(); // エサを食べます。
Animal cat = new Cat();
cat.Speak(); // ニャーニャー!
cat.Eat(); // エサを食べます。
}
}
実行結果は次のようになります:
ワンワン!
エサを食べます。
ニャーニャー!
エサを食べます。
4. 抽象クラスとインターフェースの違い
C#にはインターフェース(interface)という似た仕組みもありますが、抽象クラスとは目的が少し違います。
インターフェース:ルールだけ決める(中身なし)
抽象クラス:ルール+共通の処理も一緒に書ける
つまり、共通の機能(たとえばEatメソッドのような)を実装しておきたい場合には、抽象クラスの方が向いています。
5. 抽象クラスを使うメリットと注意点
抽象クラスを使うことで、「共通のルールを強制できる」というメリットがあります。たとえば、複数の子クラスに対して、必ず「Speak」メソッドを用意させたいときに有効です。
ただし、以下のような注意点もあります:
- 抽象クラスだけではインスタンス化できない(newできない)
- 子クラスで抽象メソッドを必ずオーバーライド(上書き)する必要がある
6. 現実世界での例えで理解しよう
抽象クラスを「動物」というテンプレートにたとえると、「動物は必ず鳴く」というルールを決めておくことができます。ただし、「どう鳴くか」は種類によって異なるので、犬はワンワン、猫はニャーニャーと、それぞれが自分のやり方を持ちます。
抽象クラス=ルールブック、
抽象メソッド=ルールブックに書かれた「やるべきことのリスト」
というイメージで覚えておくと分かりやすいです。
まとめ
抽象クラスと抽象メソッドという仕組みは、C#で複雑な処理を整理しながら拡張性の高いプログラムを作るためにとても役立つ考え方です。今回学んだ内容を振り返ると、抽象クラスは共通の性質や基本となる動作をまとめておくための土台であり、そこに記される抽象メソッドは「必ず実装するべき行動」を示すための重要な役割を持っています。こうした仕組みを使うことで、子クラスごとに振る舞いを変えながら、共通のルールを守らせることができるため、プログラム全体の統一性や管理のしやすさが向上します。 また、抽象クラスは実際のオブジェクトとして生成できないという特性を持つため、誤った使い方を防ぎ、設計そのものが自然と整理される点も魅力です。特に複数の種類に分かれるクラスをまとめて扱いたいときや、共通の機能を持ちながらも動作内容が異なるような処理に適しています。こうした特徴を理解しながらコードを書くと、拡張しやすく読みやすいプログラムを作りやすくなるでしょう。 さらに、抽象クラスとインターフェースの違いを押さえておくことも大切です。どちらもルールを定めるための仕組みですが、抽象クラスは共通処理を持てる点が大きく異なります。中身のあるメソッドを提供しておきたい場合には抽象クラスが便利で、逆に複数のクラスに共通の規則だけを設けたい場合にはインターフェースが適しています。この違いを踏まえて使い分ければ、より柔軟で意図のはっきりした設計が可能となります。 抽象クラスを活用することで、実装の強制力と自由度を両立できるため、現場の開発でもよく利用されるしくみです。たとえば動物の例のように、「必ず鳴く」というルールを決めながら、どのように鳴くかはそれぞれで自由に決められるという柔軟さを提供します。こうした設計が可能になることで、規模が大きくなってもメンテナンスしやすく、仕様変更に対応しやすい構造を保てます。 それでは学んだ内容を踏まえつつ、改めて抽象クラスを使ったサンプルコードを示しながら理解を深めていきましょう。
抽象クラスと抽象メソッドのおさらいサンプル
以下は、先ほどの内容を踏まえて少しアレンジした抽象クラスの例です。動物が「鳴く」だけでなく、「移動する」という抽象的な行動も持っていると仮定して、さらに理解を固めていきましょう。
// 抽象クラス
abstract class Creature
{
public abstract void Speak();
public abstract void Move();
public void Info()
{
Console.WriteLine("これは生き物です。");
}
}
// 子クラス:Bird
class Bird : Creature
{
public override void Speak()
{
Console.WriteLine("チュンチュン。");
}
public override void Move()
{
Console.WriteLine("羽ばたいて移動します。");
}
}
// 子クラス:Fish
class Fish : Creature
{
public override void Speak()
{
Console.WriteLine("……(魚は鳴き声が小さいです)");
}
public override void Move()
{
Console.WriteLine("水の中を泳いで移動します。");
}
}
抽象クラスの中に複数の抽象メソッドを定義することで、子クラスに「必ず実装しなければならない行動」を増やすことができます。これによって設計はさらに明確になり、クラスごとの特徴も表現しやすくなります。生き物という大きな枠組みの中で、それぞれが異なる移動方法を示すことで、抽象クラスが持つルールの強制力と柔軟性が自然に体験できるでしょう。プログラムが複雑になっても、抽象クラスを利用すれば分類や整理がしやすくなり、理解しやすい構造のまま保つことができます。
生徒
「抽象クラスって、役割を決めるためのルールブックみたいなものなんですね。子クラスはそのルールを必ず守る仕組みなんだとよく分かりました。」
先生
「そうです。実際の処理を書くのは子クラスですが、その前提となる役割を統一しておけるので、規模が大きくなっても整った形で管理できますよ。」
生徒
「インターフェースとの違いも理解できました。共通の処理を持ちたいときは抽象クラスを使うんですね。」
先生
「その通りです。必要に応じて使い分けることで、柔軟で読みやすいコードを書くことができます。ぜひ実際のプロジェクトでも意識してみてください。」
生徒
「今回のサンプルも分かりやすかったので、いろいろ応用して試してみます!」