カテゴリ: C# 更新日: 2026/06/18

C#の抽象クラスと抽象メソッドとは?実装例を交えてやさしく解説

C#の抽象クラスと抽象メソッドとは?実装例を交えて解説
C#の抽象クラスと抽象メソッドとは?実装例を交えて解説

先生と生徒の会話形式で理解しよう

生徒

「クラスの仕組みは少し分かってきたのですが、抽象クラスって何ですか?」

先生

「抽象クラスとは、"共通のルールだけを決めるための設計図"のようなクラスのことです。」

生徒

「設計図だけってことは、実際には使えないんですか?」

先生

「そのとおりです。抽象クラスだけではオブジェクトは作れません。使うには、子クラスで具体的な中身を作る必要があります。」

生徒

「なるほど!では、抽象メソッドって何ですか?」

先生

「抽象メソッドは、抽象クラスの中で定義される、“中身がないメソッド”のことです。子クラスで中身を必ず作る決まりがあります。」

1. 抽象クラスとは?

1. 抽象クラスとは?
1. 抽象クラスとは?

C#の抽象クラス(abstract class)とは、一言でいうと「他のクラスの共通部分をまとめた、未完成の設計図」のことです。プログラミング初心者の方には、「型紙」や「テンプレート」をイメージすると分かりやすいかもしれません。

例えば、「ノートPC」や「デスクトップPC」という具体的な製品を作る前に、共通して必要な「電源ボタン」や「キーボード」といった共通項目を定義した「パソコン」という大まかな枠組みを作る作業に似ています。

抽象クラスの主な特徴:

  • クラス名の前に abstract 修飾子をつける。
  • 「概念」のような存在なので、そのまま実体(インスタンス)を new して作ることはできない。
  • 共通で使う変数(フィールド)や、具体的な処理(メソッド)をあらかじめ書いておくことができる。
  • 継承した子クラスに対して「この機能は必ず作ってね」というルールを強制できる。

実際に、抽象クラスを定義する簡単なサンプルコードを見てみましょう。


using System;

// 抽象クラス:スマートフォンの共通設計図
abstract class SmartPhone
{
    // 共通で持っている変数
    public string ModelName;

    // 共通で使えるメソッド(具体的な処理を書いておける)
    public void PowerOn()
    {
        Console.WriteLine(ModelName + "の電源を入れます。");
    }

    // 子クラスで具体的に決めるメソッド(ここでは定義だけ)
    public abstract void ShowBatterySpec();
}

// 実際に使うための子クラス(iPhone)
class IPhone : SmartPhone
{
    public IPhone()
    {
        ModelName = "最新のiPhone";
    }

    // 抽象メソッドの中身を具体的に記述(オーバーライド)
    public override void ShowBatterySpec()
    {
        Console.WriteLine("バッテリー容量は20時間持続します。");
    }
}

class Program
{
    static void Main()
    {
        // SmartPhone phone = new SmartPhone(); // エラー!抽象クラスは直接作れません。

        IPhone myPhone = new IPhone();
        myPhone.PowerOn();         // 共通メソッドの呼び出し
        myPhone.ShowBatterySpec(); // 子クラスで決めたメソッドの呼び出し
    }
}

実行結果は以下のようになります:


最新のiPhoneの電源を入れます。
バッテリー容量は20時間持続します。

このように、抽象クラスを使うことで、プログラムの重複をなくし、チーム開発でも「誰が作っても共通のルールが守られる」という安全なコードを書くことができるようになります。後続のセクションでは、この中にある「抽象メソッド」についてより深く掘り下げていきます。

2. 抽象メソッドとは?

2. 抽象メソッドとは?
2. 抽象メソッドとは?

抽象メソッド(abstract method)とは、メソッドの名前や型(引数や戻り値)といった「外枠」だけを定義し、具体的な「中身(処理内容)」を一切書かない特別なメソッドのことです。

抽象クラスの中にこのメソッドを記述しておくことで、そのクラスを継承した子クラスに対して、「この名前のメソッドを必ず実装(オーバーライド)してください」という強制力のあるルールを課すことができます。これは、大規模な開発で「作り忘れ」を防ぐための非常に強力な仕組みです。

書き方の重要なポイント:

  • 修飾子に abstract キーワードを付ける。
  • メソッドの中身を記述する中括弧 { } を書かず、末尾をセミコロン ; で閉じる。
  • 抽象メソッドを持つクラス自体も、必ず abstract class(抽象クラス)である必要がある。

プログラミングが初めての方でもイメージしやすいよう、「お絵描きアプリ」を例にしたシンプルなコードを見てみましょう。「図形」という抽象的なルールを作り、具体的な「円」で中身を完成させる流れです。


using System;

// 抽象クラス:図形という大まかな枠組み
abstract class Shape
{
    // 抽象メソッド:「描画する」という名前とルールだけ決める
    // 中身(どう描くか)はここでは書かない
    public abstract void Draw();
}

// 具体的なクラス:円(Shapeを継承)
class Circle : Shape
{
    // 親クラスで決めた「Draw」の中身を具体的に作る
    public override void Draw()
    {
        Console.WriteLine("画面に丸い円を描きました。");
    }
}

class Program
{
    static void Main()
    {
        // Shapeクラスを継承したCircleクラスを使う
        Circle myCircle = new Circle();
        myCircle.Draw();
    }
}

実行結果は以下のようになります:


画面に丸い円を描きました。

この例では、Shapeクラスで「図形なら必ず描画(Draw)ができるはずだ」というルールだけを決め、実際の描き方はCircleクラスに任せています。もし子クラスでDrawメソッドを書かなければ、ビルドエラー(プログラムの実行前のチェック)で教えてくれるため、安全にプログラムを組むことができるのです。

3. 抽象クラスと抽象メソッドのサンプルコード

3. 抽象クラスと抽象メソッドのサンプルコード
3. 抽象クラスと抽象メソッドのサンプルコード

抽象クラスと抽象メソッドの役割をより深く理解するために、身近な「飲み物の自動販売機」を例に挙げたプログラムを見てみましょう。

「自動販売機」という共通の枠組み(抽象クラス)を作り、具体的な「お茶の販売機」や「コーラの販売機」で、それぞれ異なる「ボタンを押した時の動作」を実装するイメージです。これにより、どの販売機でも「お金を入れてボタンを押す」という基本操作が統一されます。


using System;

// 抽象クラス:自動販売機のテンプレート
abstract class VendingMachine
{
    // 共通のプロパティ(販売機の名前)
    public string MachineName;

    // 抽象メソッド:ボタンを押した時の動き
    // 飲み物によって出てくるものが違うため、ここでは中身を書かない
    public abstract void PushButton();

    // 共通メソッド:お金を入れる動作
    // どの販売機でも共通の処理なので、ここで具体的に書いておく
    public void InsertCoin(int amount)
    {
        Console.WriteLine(MachineName + "に" + amount + "円入れました。");
    }
}

// 具体的なクラス:お茶専用の販売機
class TeaMachine : VendingMachine
{
    public TeaMachine()
    {
        MachineName = "お茶の販売機";
    }

    // 親クラスの抽象メソッドを「override」して中身を具体的に作る
    public override void PushButton()
    {
        Console.WriteLine("冷たい緑茶が出てきました。");
    }
}

// 具体的なクラス:コーラ専用の販売機
class ColaMachine : VendingMachine
{
    public ColaMachine()
    {
        MachineName = "コーラの販売機";
    }

    public override void PushButton()
    {
        Console.WriteLine("炭酸たっぷりのコーラが出てきました。");
    }
}

class Program
{
    static void Main()
    {
        // お茶の販売機のインスタンスを作成
        TeaMachine myTea = new TeaMachine();
        myTea.InsertCoin(160); // 共通メソッドの呼び出し
        myTea.PushButton();    // 具体的なメソッドの呼び出し

        Console.WriteLine("--------------------");

        // コーラの販売機のインスタンスを作成
        ColaMachine myCola = new ColaMachine();
        myCola.InsertCoin(180);
        myCola.PushButton();
    }
}

実行結果は以下のようになります:


お茶の販売機に160円入れました。
冷たい緑茶が出てきました。
--------------------
コーラの販売機に180円入れました。
炭酸たっぷりのコーラが出てきました。

このサンプルでは、VendingMachineという抽象クラスが「お金を入れる(InsertCoin)」という共通の振る舞いを提供しつつ、「ボタンを押す(PushButton)」という具体的な中身が必要な処理を子クラスに強制しています。

プログラミング未経験の方にとって重要なのは、抽象クラスを使うことで「この機能(メソッド)を実装し忘れる」というミスを、コンピュータが事前に「エラー」として指摘してくれる点です。これにより、大人数での開発や、複雑なシステム作りでもミスを最小限に抑えることが可能になります。

4. 抽象クラスとインターフェースの違い

4. 抽象クラスとインターフェースの違い
4. 抽象クラスとインターフェースの違い

C#にはインターフェース(interface)という似た仕組みもありますが、抽象クラスとは目的が少し違います。

インターフェース:ルールだけ決める(中身なし)

抽象クラス:ルール+共通の処理も一緒に書ける

つまり、共通の機能(たとえばEatメソッドのような)を実装しておきたい場合には、抽象クラスの方が向いています。

5. 抽象クラスを使うメリットと注意点

5. 抽象クラスを使うメリットと注意点
5. 抽象クラスを使うメリットと注意点

抽象クラスを使うことで、「共通のルールを強制できる」というメリットがあります。たとえば、複数の子クラスに対して、必ず「Speak」メソッドを用意させたいときに有効です。

ただし、以下のような注意点もあります:

  • 抽象クラスだけではインスタンス化できない(newできない)
  • 子クラスで抽象メソッドを必ずオーバーライド(上書き)する必要がある

6. 現実世界での例えで理解しよう

6. 現実世界での例えで理解しよう
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("水の中を泳いで移動します。");
    }
}

抽象クラスの中に複数の抽象メソッドを定義することで、子クラスに「必ず実装しなければならない行動」を増やすことができます。これによって設計はさらに明確になり、クラスごとの特徴も表現しやすくなります。生き物という大きな枠組みの中で、それぞれが異なる移動方法を示すことで、抽象クラスが持つルールの強制力と柔軟性が自然に体験できるでしょう。プログラムが複雑になっても、抽象クラスを利用すれば分類や整理がしやすくなり、理解しやすい構造のまま保つことができます。

先生と生徒の振り返り会話

生徒

「抽象クラスって、役割を決めるためのルールブックみたいなものなんですね。子クラスはそのルールを必ず守る仕組みなんだとよく分かりました。」

先生

「そうです。実際の処理を書くのは子クラスですが、その前提となる役割を統一しておけるので、規模が大きくなっても整った形で管理できますよ。」

生徒

「インターフェースとの違いも理解できました。共通の処理を持ちたいときは抽象クラスを使うんですね。」

先生

「その通りです。必要に応じて使い分けることで、柔軟で読みやすいコードを書くことができます。ぜひ実際のプロジェクトでも意識してみてください。」

生徒

「今回のサンプルも分かりやすかったので、いろいろ応用して試してみます!」

カテゴリの一覧へ
新着記事
New1
COBOL
COBOLシステムのセキュリティを強化する!セキュリティベンダーとの連携と管理のコツ
New2
COBOL
COBOLのプログラム分割とパフォーマンスの関係をやさしく解説!初心者でも理解できる構造化プログラミング入門
New3
COBOL
COBOLのモジュール化の基本設計を完全ガイド!初心者でもわかる保守性と可読性の向上テクニック
New4
C#
C#セキュリティ対策完全ガイド!初心者向けアプリ開発の脆弱性対策とベストプラクティス
人気記事
No.1
Java&Spring記事人気No1
C#
C#の文字列を数値に変換する方法(int.Parse・TryParse)をわかりやすく解説!
No.2
Java&Spring記事人気No2
C#
C#のラムダ式の書き方と構文を初心者向けに完全解説
No.3
Java&Spring記事人気No3
C#
C#のbool型を完全解説!初心者でもわかるtrueとfalseの基本と使い方
No.4
Java&Spring記事人気No4
C#
C#のトランザクション処理を完全ガイド!初心者でもわかるCommit・Rollbackの使い方
No.5
Java&Spring記事人気No5
COBOL
COBOLの数値データ型「PIC 9」の使い方と注意点をやさしく解説!
No.6
Java&Spring記事人気No6
Azure
Azureストレージの冗長性比較!LRS/GRS/ZRSの選び方とコストの最適解を完全解説
No.7
Java&Spring記事人気No7
C#
C#のLINQでOrderByを使った並び替えを完全ガイド!初心者でもわかるソート方法
No.8
Java&Spring記事人気No8
C#
C#のpartialクラスとは?初心者でも理解できるクラス分割の基本