C#抽象メソッドとは?abstractの使い方・実装方法・overrideまで初心者向けに解説

はじめに

C#を学び始めると、クラス、継承、overrideなどと一緒に「抽象メソッド」という言葉が出てきます。抽象メソッドは、オブジェクト指向プログラミングでよく使われる重要な仕組みです。

C#の抽象メソッドは、簡単に言うと「処理内容を派生クラスに任せるメソッド」です。親クラスではメソッド名や戻り値、引数だけを決めておき、具体的な処理は子クラス側で実装します。

この記事では、C#の抽象メソッドとは何か、abstractキーワードの使い方、overrideによる実装方法、通常メソッドやインターフェースとの違いまで、初心者にもわかりやすく解説します。

1. C#の抽象メソッドとは?

C#の抽象メソッドは、抽象クラスの中で定義される「中身のないメソッド」です。親クラスでは「このメソッドを必ず用意してください」というルールだけを決め、実際の処理は派生クラスで書きます。

たとえば、動物を表すクラスを考えてみましょう。すべての動物には「鳴く」という動作がありますが、犬は「ワン」、猫は「ニャー」と鳴き方が異なります。このような場合に、親クラスで「鳴く」というメソッドだけを決めておき、具体的な鳴き声は子クラスで実装できます。

1-1. 抽象メソッドの基本的な意味

抽象メソッドとは、メソッドの名前、戻り値、引数だけを定義し、処理内容を持たないメソッドです。

C#では、抽象メソッドを定義するときにabstractキーワードを使います。

C#
public abstract void Speak();

このコードは、「Speakというメソッドを必ず実装してください」という意味になります。ただし、この時点ではSpeakメソッドの中身はありません。

抽象メソッドは、派生クラスに対して実装を強制するために使われます。つまり、設計上「このメソッドは必ず必要」と決めたいときに便利です。

1-2. 抽象メソッドは「処理内容を持たないメソッド」

通常のメソッドは、次のように { } の中に処理を書きます。

C#
public void ShowMessage()
{
Console.WriteLine("こんにちは");
}

一方、抽象メソッドには処理本体を書きません。

C#
public abstract void ShowMessage();

抽象メソッドでは、メソッドの最後にセミコロン;を付けます。波かっこ{ }を書いてはいけません。

次のように書くとエラーになります。

C#
public abstract void ShowMessage()
{
Console.WriteLine("こんにちは");
}

抽象メソッドは、あくまで「このメソッドが存在すること」を定義するだけです。具体的な処理は、継承したクラスがoverrideを使って実装します。

1-3. 派生クラスで必ず実装する必要がある理由

抽象メソッドは、派生クラスで必ず実装しなければなりません。

理由は、抽象メソッドには処理内容がないためです。もし派生クラスで実装しないまま使おうとすると、呼び出されたときに何をすればよいのかわかりません。

そのためC#では、抽象クラスを継承したクラスは、すべての抽象メソッドを実装する必要があります。

C#
public abstract class Animal
{
public abstract void Speak();
}

public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}

この例では、AnimalクラスにSpeakという抽象メソッドがあります。DogクラスはAnimalクラスを継承しているため、Speakメソッドをoverrideして実装しています。

1-4. 抽象メソッドが使われる代表的な場面

抽象メソッドは、共通のルールはあるけれど、具体的な処理がクラスごとに異なる場面でよく使われます。

たとえば、次のような場面です。

図形クラスでは、すべての図形に「面積を求める」という処理があります。しかし、四角形、三角形、円では面積の計算方法が異なります。

決済処理では、すべての決済方法に「支払う」という処理があります。しかし、クレジットカード、銀行振込、QRコード決済では実際の処理が異なります。

ファイル出力では、すべての出力形式に「保存する」という処理があります。しかし、CSV、JSON、XMLでは保存形式が異なります。

このように、「共通のメソッド名は決めたいが、処理内容は個別に変えたい」ときに抽象メソッドが役立ちます。

2. C#のabstractキーワードの基本

C#で抽象クラスや抽象メソッドを定義するときには、abstractキーワードを使います。abstractは「抽象的な」「未完成の」という意味を持つキーワードです。

abstractを付けたクラスやメソッドは、そのままでは完全な処理を持たないため、継承先で具体的に実装することを前提としています。

2-1. abstractとは何か

abstractとは、クラスやメソッドなどに対して「これは抽象的な定義です」と示すためのキーワードです。

抽象的な定義とは、具体的な処理をすべて書くのではなく、共通の型やルールだけを決めておくことです。

たとえば、次のように書きます。

C#
public abstract class Animal
{
public abstract void Speak();
}

この例では、Animalクラスは抽象クラスです。そして、Speakメソッドは抽象メソッドです。

Animalクラスは「動物」という大きな概念を表しています。しかし、「動物がどう鳴くか」は動物の種類によって異なるため、Speakメソッドの具体的な処理は書いていません。

2-2. abstractを使える対象

C#のabstractは、主に次のような対象に使えます。

C#
public abstract class SampleClass
{
}
C#
public abstract void SampleMethod();

一般的に初心者が最初に覚えるべきなのは、抽象クラスと抽象メソッドです。

抽象クラスは、継承されることを前提にしたクラスです。抽象メソッドは、派生クラスで実装されることを前提にしたメソッドです。

抽象メソッドを使うには、基本的に抽象クラスの中に書く必要があります。

2-3. 抽象クラスと抽象メソッドの関係

抽象メソッドは、抽象クラスの中で定義します。

C#
public abstract class BaseClass
{
public abstract void Execute();
}

抽象メソッドを1つでも持つクラスは、必ず抽象クラスにしなければなりません。

つまり、次のような関係があります。

抽象メソッドは未完成のメソッドです。未完成のメソッドを含むクラスも、そのままでは完成したクラスとは言えません。そのため、そのクラス自体もabstractを付けて抽象クラスにする必要があります。

C#
public class BaseClass
{
public abstract void Execute();
}

このように、通常のクラスの中に抽象メソッドを書くことはできません。BaseClassabstractが付いていないため、コンパイルエラーになります。

2-4. abstractを付けると何が変わるのか

クラスにabstractを付けると、そのクラスはインスタンス化できなくなります。

C#
public abstract class Animal
{
}
C#
Animal animal = new Animal();

このようなコードはエラーになります。抽象クラスは未完成の設計図のようなものなので、そのままオブジェクトを作ることはできません。

メソッドにabstractを付けると、そのメソッドには処理本体を書けなくなります。そして、派生クラスでoverrideして実装する必要があります。

つまり、abstractを付けることで「これは継承先で完成させるものです」という意味になります。

3. C#抽象メソッドの書き方

C#で抽象メソッドを書くには、抽象クラスの中でメソッドにabstractキーワードを付けます。抽象メソッドには処理本体を書かず、最後にセミコロンを付けます。

3-1. 抽象メソッドの基本構文

抽象メソッドの基本構文は次のとおりです。

C#
アクセス修飾子 abstract 戻り値の型 メソッド名(引数);

実際のコードでは、次のようになります。

C#
public abstract class SampleBase
{
public abstract void Execute();
}

この例では、Executeメソッドが抽象メソッドです。戻り値はvoidで、引数はありません。

抽象メソッドは、「このクラスを継承するクラスは、Executeメソッドを必ず実装してください」という意味になります。

3-2. 抽象メソッドには処理本体を書けない

抽象メソッドには、処理本体を書くことはできません。

正しい書き方は次のとおりです。

C#
public abstract void Execute();

間違った書き方は次のとおりです。

C#
public abstract void Execute()
{
Console.WriteLine("実行します");
}

抽象メソッドは、処理を持たないメソッドです。そのため、{ }を使って処理を書くとエラーになります。

処理を書きたい場合は、抽象メソッドではなく通常メソッド、またはvirtualメソッドを使います。

3-3. 抽象メソッドは抽象クラス内で定義する

抽象メソッドは、抽象クラスの中で定義します。

C#
public abstract class BaseTask
{
public abstract void Run();
}

抽象クラスではない通常のクラスに抽象メソッドを書くことはできません。

C#
public class BaseTask
{
public abstract void Run();
}

このコードはエラーになります。抽象メソッドを含むクラスは、必ずabstract classとして定義する必要があります。

3-4. 戻り値・引数ありの抽象メソッドの書き方

抽象メソッドには、戻り値や引数を指定できます。

C#
public abstract class Calculator
{
public abstract int Calculate(int a, int b);
}

この例では、Calculateメソッドはint型の値を返し、int aint bという2つの引数を受け取ります。

派生クラスでは、同じ戻り値、同じメソッド名、同じ引数で実装する必要があります。

C#
public class AddCalculator : Calculator
{
public override int Calculate(int a, int b)
{
return a + b;
}
}

このように、抽象メソッドでも通常のメソッドと同じように、戻り値や引数を設計できます。

4. C#抽象メソッドの実装方法

C#の抽象メソッドを実装するには、抽象クラスを継承し、派生クラス側でoverrideキーワードを使います。

抽象メソッドは親クラスで処理を持っていないため、子クラスで必ず具体的な処理を書かなければなりません。

4-1. 抽象クラスを継承する方法

抽象クラスを継承するには、通常のクラス継承と同じようにコロン:を使います。

C#
public abstract class Animal
{
public abstract void Speak();
}

public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}

Dog : Animalは、「DogクラスはAnimalクラスを継承します」という意味です。

AnimalクラスにはSpeakという抽象メソッドがあるため、DogクラスではSpeakメソッドを実装する必要があります。

4-2. overrideを使って抽象メソッドを実装する

抽象メソッドを派生クラスで実装するときは、overrideキーワードを使います。

C#
public override void Speak()
{
Console.WriteLine("ワン");
}

overrideは、「親クラスで定義されたメソッドを上書きして実装します」という意味です。

抽象メソッドの場合、親クラスに処理本体はありませんが、メソッドの定義は存在しています。その定義に対して、派生クラスで具体的な処理を与えるのがoverrideです。

4-3. 実装しない場合に発生するコンパイルエラー

抽象クラスを継承したにもかかわらず、抽象メソッドを実装しないとコンパイルエラーになります。

C#
public abstract class Animal
{
public abstract void Speak();
}

public class Dog : Animal
{
}

このコードでは、DogクラスがAnimalクラスを継承していますが、Speakメソッドを実装していません。

そのため、Dogクラスも未完成のクラスとみなされます。解決方法は2つあります。

1つ目は、Speakメソッドをoverrideして実装することです。

C#
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}

2つ目は、Dogクラス自体も抽象クラスにすることです。

C#
public abstract class Dog : Animal
{
}

ただし、通常は具体的なクラスとして使いたい場合が多いため、抽象メソッドを実装する方法を選びます。

4-4. 複数の抽象メソッドを実装する例

抽象メソッドは、1つの抽象クラスに複数定義できます。

C#
public abstract class Report
{
public abstract void Create();
public abstract void Print();
public abstract void Save();
}

この抽象クラスを継承するクラスでは、すべての抽象メソッドを実装する必要があります。

C#
public class SalesReport : Report
{
public override void Create()
{
Console.WriteLine("売上レポートを作成します");
}

public override void Print()
{
Console.WriteLine("売上レポートを印刷します");
}

public override void Save()
{
Console.WriteLine("売上レポートを保存します");
}
}

1つでも実装を忘れるとエラーになります。抽象メソッドは、派生クラスに必要な処理を強制する仕組みだと覚えておきましょう。

5. abstractとoverrideの関係

C#の抽象メソッドを理解するうえで、abstractoverrideの関係は非常に重要です。

親クラスではabstractを使って「このメソッドを実装してください」と定義します。子クラスではoverrideを使って「そのメソッドを実装します」と書きます。

5-1. overrideとは何か

overrideとは、親クラスで定義されたメソッドを派生クラスで上書きするためのキーワードです。

抽象メソッドだけでなく、virtualメソッドを上書きするときにも使います。

C#
public class BaseClass
{
public virtual void Show()
{
Console.WriteLine("BaseClassのShow");
}
}

public class ChildClass : BaseClass
{
public override void Show()
{
Console.WriteLine("ChildClassのShow");
}
}

このように、親クラスのメソッドを子クラスで別の処理に変えるときにoverrideを使います。

5-2. 抽象メソッドにoverrideが必要な理由

抽象メソッドは、親クラスでメソッドの形だけを定義しています。

C#
public abstract void Execute();

派生クラスでは、その定義をもとに具体的な処理を書きます。

C#
public override void Execute()
{
Console.WriteLine("処理を実行します");
}

overrideを付けることで、C#コンパイラに「これは親クラスの抽象メソッドを実装しているものです」と伝えます。

overrideを書かないと、新しいメソッドを作ろうとしていると判断されるため、抽象メソッドを実装したことになりません。

5-3. abstractメソッドとvirtualメソッドの違い

abstractメソッドとvirtualメソッドは、どちらも派生クラスで上書きできます。しかし、大きな違いがあります。

abstractメソッドは処理本体を持ちません。派生クラスで必ず実装する必要があります。

C#
public abstract void Execute();

virtualメソッドは処理本体を持てます。派生クラスで必要に応じて上書きできます。

C#
public virtual void Execute()
{
Console.WriteLine("基本処理を実行します");
}

つまり、必ず派生クラスに実装させたい場合はabstractを使います。共通の標準処理を用意しつつ、必要なら上書きできるようにしたい場合はvirtualを使います。

5-4. overrideし忘れやすいポイント

初心者がよく間違えるのは、派生クラス側でoverrideを書き忘れることです。

C#
public class Dog : Animal
{
public void Speak()
{
Console.WriteLine("ワン");
}
}

このようにoverrideを書かないと、親クラスの抽象メソッドを実装したことになりません。

正しくは次のように書きます。

C#
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}

また、戻り値や引数、アクセス修飾子が親クラスの抽象メソッドと一致していない場合もエラーになります。

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

ここでは、C#の抽象クラスと抽象メソッドを使ったサンプルコードを紹介します。実際にコードを書きながら確認すると、抽象メソッドの役割が理解しやすくなります。

6-1. 基本的な抽象クラスのサンプル

まずは、もっとも基本的な抽象クラスの例です。

C#
using System;

public abstract class BaseProcess
{
public abstract void Execute();
}

public class LoginProcess : BaseProcess
{
public override void Execute()
{
Console.WriteLine("ログイン処理を実行します");
}
}

public class Program
{
public static void Main()
{
LoginProcess process = new LoginProcess();
process.Execute();
}
}

実行結果は次のようになります。

ログイン処理を実行します

BaseProcessクラスでは、Executeメソッドの名前だけを決めています。実際の処理は、LoginProcessクラスで実装しています。

6-2. 図形クラスで面積を求めるサンプル

次に、図形の面積を求める例を見てみましょう。

C#
using System;

public abstract class Shape
{
public abstract double GetArea();
}

public class Rectangle : Shape
{
private double width;
private double height;

public Rectangle(double width, double height)
{
this.width = width;
this.height = height;
}

public override double GetArea()
{
return width * height;
}
}

public class Circle : Shape
{
private double radius;

public Circle(double radius)
{
this.radius = radius;
}

public override double GetArea()
{
return radius * radius * Math.PI;
}
}

public class Program
{
public static void Main()
{
Shape rectangle = new Rectangle(5, 3);
Shape circle = new Circle(2);

Console.WriteLine(rectangle.GetArea());
Console.WriteLine(circle.GetArea());
}
}

Shapeクラスでは、GetAreaという抽象メソッドを定義しています。四角形と円では面積の計算方法が異なるため、それぞれの派生クラスで別々に実装しています。

このように、同じGetAreaというメソッド名でも、クラスによって異なる処理を実行できます。

6-3. 動物クラスで鳴き声を実装するサンプル

動物の鳴き声を表す例も、抽象メソッドの理解に適しています。

C#
using System;

public abstract class Animal
{
public abstract void Speak();
}

public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}

public class Cat : Animal
{
public override void Speak()
{
Console.WriteLine("ニャー");
}
}

public class Program
{
public static void Main()
{
Animal dog = new Dog();
Animal cat = new Cat();

dog.Speak();
cat.Speak();
}
}

実行結果は次のとおりです。

ワン
ニャー

Animalクラスでは「鳴く」というルールだけを定義しています。犬と猫では鳴き声が異なるため、それぞれのクラスでSpeakメソッドを実装しています。

6-4. 実務でイメージしやすい処理フローの例

実務では、処理の流れを共通化し、一部の処理だけを派生クラスに任せる設計で抽象メソッドが使われることがあります。

C#
using System;

public abstract class DataImporter
{
public void Import()
{
ReadData();
ValidateData();
SaveData();
}

protected abstract void ReadData();

protected virtual void ValidateData()
{
Console.WriteLine("データを検証します");
}

protected abstract void SaveData();
}

public class CsvImporter : DataImporter
{
protected override void ReadData()
{
Console.WriteLine("CSVファイルを読み込みます");
}

protected override void SaveData()
{
Console.WriteLine("CSVデータを保存します");
}
}

public class Program
{
public static void Main()
{
DataImporter importer = new CsvImporter();
importer.Import();
}
}

この例では、Importメソッドで全体の流れを決めています。

ReadDataSaveDataは抽象メソッドなので、派生クラスで必ず実装します。一方、ValidateDatavirtualメソッドなので、必要に応じて上書きできます。

このように、共通の処理フローを親クラスで管理し、個別の処理だけを子クラスに任せることができます。

7. 抽象メソッドと通常メソッドの違い

C#の抽象メソッドと通常メソッドの大きな違いは、処理本体を持てるかどうかです。

通常メソッドはそのクラス内で処理を完結できます。一方、抽象メソッドは処理を持たず、派生クラスで実装する必要があります。

7-1. 通常メソッドは処理を持てる

通常メソッドは、メソッドの中に処理を書くことができます。

C#
public class Message
{
public void Show()
{
Console.WriteLine("メッセージを表示します");
}
}

このShowメソッドは、呼び出すとすぐに処理を実行できます。継承しなくても使えます。

通常メソッドは、処理内容がすでに決まっている場合に使います。

7-2. 抽象メソッドは処理を持てない

抽象メソッドは、処理本体を持てません。

C#
public abstract class MessageBase
{
public abstract void Show();
}

このShowメソッドは、呼び出すための具体的な処理を持っていません。そのため、派生クラスで必ず実装する必要があります。

C#
public class ErrorMessage : MessageBase
{
public override void Show()
{
Console.WriteLine("エラーメッセージを表示します");
}
}

抽象メソッドは、処理内容がクラスごとに異なる場合に使います。

7-3. 抽象クラス内では通常メソッドも定義できる

抽象クラスの中には、抽象メソッドだけでなく通常メソッドも定義できます。

C#
public abstract class Worker
{
public void Start()
{
Console.WriteLine("作業を開始します");
}

public abstract void Work();
}

この例では、Startメソッドは通常メソッドです。すべての派生クラスで共通して使えます。

一方、Workメソッドは抽象メソッドです。作業内容は派生クラスによって異なるため、子クラス側で実装します。

7-4. 使い分けの判断基準

通常メソッドを使うべきなのは、すべてのクラスで共通の処理を使いたい場合です。

抽象メソッドを使うべきなのは、メソッド名や呼び出し方は共通にしたいが、処理内容は派生クラスごとに変えたい場合です。

たとえば、「ログを出力する」「開始メッセージを表示する」といった処理が全クラスで同じなら通常メソッドが向いています。

一方、「ファイルを読み込む」「料金を計算する」「面積を求める」など、種類によって処理が変わるものは抽象メソッドが向いています。

8. 抽象メソッドとインターフェースの違い

C#で抽象メソッドを学ぶと、インターフェースとの違いも気になるポイントです。抽象クラスとインターフェースは似ていますが、目的や使い方が異なります。

8-1. インターフェースとは何か

インターフェースは、クラスが実装すべき機能のルールを定義する仕組みです。

C#
public interface IPrintable
{
void Print();
}

この例では、IPrintableインターフェースにPrintメソッドが定義されています。

このインターフェースを実装するクラスは、Printメソッドを用意する必要があります。

C#
public class Report : IPrintable
{
public void Print()
{
Console.WriteLine("レポートを印刷します");
}
}

インターフェースは、「この機能を持っていること」を表すためによく使われます。

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

抽象クラスは、共通の処理や状態を持ちながら、一部の処理を派生クラスに任せるときに使います。

C#
public abstract class Animal
{
public string Name { get; set; }

public void Sleep()
{
Console.WriteLine("眠ります");
}

public abstract void Speak();
}

このように、抽象クラスにはフィールド、プロパティ、通常メソッド、抽象メソッドを含めることができます。

一方、インターフェースは、基本的に「何ができるか」という契約を表します。

C#
public interface IMovable
{
void Move();
}

クラスは1つのクラスしか継承できませんが、複数のインターフェースを実装できます。

C#
public class Robot : IMovable, IPrintable
{
public void Move()
{
Console.WriteLine("移動します");
}

public void Print()
{
Console.WriteLine("印刷します");
}
}

抽象クラスは「共通の土台」、インターフェースは「機能の約束」と考えると理解しやすいです。

8-3. 抽象メソッドを使うべきケース

抽象メソッドを使うべきなのは、共通の親クラスとしての意味があり、派生クラスに一部の処理を強制したい場合です。

たとえば、Animalという抽象クラスを作り、DogCatSpeakメソッドを実装させるようなケースです。

C#
public abstract class Animal
{
public abstract void Speak();

public void Sleep()
{
Console.WriteLine("眠ります");
}
}

このように、共通処理も持たせたい場合は抽象クラスが向いています。

また、処理の流れを親クラスで決め、一部だけを子クラスに任せたい場合にも抽象メソッドが便利です。

8-4. インターフェースを使うべきケース

インターフェースを使うべきなのは、クラス同士に親子関係はないけれど、共通の機能を持たせたい場合です。

たとえば、プリンター、レポート、画像などは別々の種類のクラスですが、どれも「印刷できる」という機能を持つことがあります。

C#
public interface IPrintable
{
void Print();
}

このような場合は、抽象クラスよりもインターフェースが向いています。

また、複数の機能を組み合わせたい場合もインターフェースが便利です。

C#
public class Document : IPrintable, ISavable
{
public void Print()
{
Console.WriteLine("印刷します");
}

public void Save()
{
Console.WriteLine("保存します");
}
}

抽象クラスは継承できるのが1つだけですが、インターフェースは複数実装できるため、柔軟な設計ができます。

9. C#抽象メソッドでよくあるエラー

C#の抽象メソッドでは、書き方を少し間違えるだけでコンパイルエラーになります。ここでは、初心者が特につまずきやすいエラーを紹介します。

9-1. 抽象メソッドに処理本体を書いてしまう

抽象メソッドに処理本体を書くとエラーになります。

C#
public abstract class Sample
{
public abstract void Execute()
{
Console.WriteLine("実行します");
}
}

抽象メソッドは処理を持たないメソッドなので、{ }を書いてはいけません。

正しくは次のように書きます。

C#
public abstract class Sample
{
public abstract void Execute();
}

処理を書きたい場合は、抽象メソッドではなく通常メソッドにします。

C#
public void Execute()
{
Console.WriteLine("実行します");
}

9-2. 抽象クラス以外に抽象メソッドを書く

抽象メソッドは、抽象クラスの中で定義する必要があります。

C#
public class Sample
{
public abstract void Execute();
}

このコードはエラーになります。Sampleクラスにabstractが付いていないためです。

正しくは次のように書きます。

C#
public abstract class Sample
{
public abstract void Execute();
}

抽象メソッドを含むクラスは、必ず抽象クラスにする必要があります。

9-3. overrideを書き忘れる

抽象メソッドを派生クラスで実装するときは、overrideが必要です。

間違った例は次のとおりです。

C#
public class Child : Sample
{
public void Execute()
{
Console.WriteLine("実行します");
}
}

正しくは次のように書きます。

C#
public class Child : Sample
{
public override void Execute()
{
Console.WriteLine("実行します");
}
}

overrideを書かないと、親クラスの抽象メソッドを実装したことになりません。

9-4. アクセス修飾子や引数が一致していない

抽象メソッドを実装するときは、戻り値、メソッド名、引数が親クラスの定義と一致している必要があります。

C#
public abstract class Calculator
{
public abstract int Calculate(int a, int b);
}

次のコードは、引数が一致していないためエラーになります。

C#
public class AddCalculator : Calculator
{
public override int Calculate(int a)
{
return a;
}
}

正しくは次のように書きます。

C#
public class AddCalculator : Calculator
{
public override int Calculate(int a, int b)
{
return a + b;
}
}

抽象メソッドを実装するときは、親クラスの定義と完全に対応しているか確認しましょう。

10. C#抽象メソッドを使うメリット

C#の抽象メソッドを使うと、クラス設計に明確なルールを作ることができます。特に、複数の派生クラスで共通のメソッドを必ず持たせたい場合に便利です。

10-1. 派生クラスに実装を強制できる

抽象メソッドの最大のメリットは、派生クラスに実装を強制できることです。

C#
public abstract class Payment
{
public abstract void Pay();
}

このPaymentクラスを継承するクラスは、必ずPayメソッドを実装しなければなりません。

C#
public class CreditCardPayment : Payment
{
public override void Pay()
{
Console.WriteLine("クレジットカードで支払います");
}
}

実装を忘れるとコンパイルエラーになるため、必要な処理の漏れを防げます。

10-2. 共通の設計ルールを作れる

抽象メソッドを使うと、複数のクラスに共通の設計ルールを持たせることができます。

たとえば、すべてのレポートクラスにCreateメソッドを持たせたい場合、次のように設計できます。

C#
public abstract class ReportBase
{
public abstract void Create();
}

これにより、SalesReportUserReportなどの派生クラスは、必ずCreateメソッドを実装することになります。

クラスごとにメソッド名がバラバラになることを防げるため、コードの見通しがよくなります。

10-3. コードの拡張性が高まる

抽象メソッドを使うと、新しいクラスを追加しやすくなります。

たとえば、決済処理を抽象クラスで設計しておけば、新しい決済方法を追加するときも、同じルールに従ってクラスを作成できます。

C#
public abstract class Payment
{
public abstract void Pay();
}
C#
public class BankTransferPayment : Payment
{
public override void Pay()
{
Console.WriteLine("銀行振込で支払います");
}
}

このように、新しい機能を追加しても既存の設計を崩しにくくなります。

10-4. チーム開発で実装漏れを防げる

チーム開発では、複数人が同じ設計ルールに従ってコードを書く必要があります。

抽象メソッドを使えば、「このクラスを継承するなら、このメソッドは必ず実装する」というルールをコード上で表現できます。

ドキュメントだけでルールを伝えると、実装漏れが起きることがあります。しかし、抽象メソッドなら実装しないとコンパイルエラーになるため、ミスを早い段階で発見できます。

これは、保守性の高いコードを書くうえで大きなメリットです。

11. C#抽象メソッドを使うときの注意点

抽象メソッドは便利ですが、使い方を間違えるとクラス構造が複雑になります。すべての処理を抽象化すればよいわけではありません。

11-1. 抽象クラスはインスタンス化できない

抽象メソッドを含む抽象クラスは、そのままインスタンス化できません。

C#
public abstract class Animal
{
public abstract void Speak();
}
C#
Animal animal = new Animal();

このコードはエラーになります。

抽象クラスは未完成のクラスです。実際にオブジェクトを作るには、抽象クラスを継承した具体的なクラスを使います。

C#
Animal animal = new Dog();

このように、変数の型として抽象クラスを使い、実体として派生クラスを代入することはできます。

11-2. 継承前提の設計になる

抽象メソッドは、継承を前提とした設計です。そのため、継承関係が本当に必要かを考えることが重要です。

単に同じメソッド名を持たせたいだけなら、インターフェースの方が適している場合もあります。

また、継承を使うと親クラスと子クラスの関係が強くなります。親クラスの設計変更が、派生クラス全体に影響することもあります。

抽象クラスを作るときは、「共通の土台として本当に必要か」を意識しましょう。

11-3. 使いすぎると構造が複雑になる

抽象メソッドを多用しすぎると、どのクラスで何が実装されているのか分かりにくくなることがあります。

特に、抽象クラスが何階層にも分かれていると、初心者には追いかけるのが難しくなります。

C#
BaseClass
MiddleClass
ChildClass

このような継承階層が深くなると、処理の流れを理解しにくくなります。

抽象メソッドは、必要な場面でだけ使うことが大切です。すべてを抽象化しようとせず、シンプルな設計を心がけましょう。

11-4. 初心者が混同しやすいポイント

初心者が混同しやすいのは、abstractvirtualoverride、インターフェースの違いです。

abstractは、処理を持たず、派生クラスで必ず実装させるものです。

virtualは、処理を持ち、必要に応じて派生クラスで上書きできるものです。

overrideは、親クラスのabstractメソッドやvirtualメソッドを派生クラスで実装または上書きするものです。

インターフェースは、クラスに特定の機能を持たせるための契約です。

最初はすべてを完璧に理解しようとせず、まずは「抽象メソッドは中身がなく、overrideで実装する」と覚えるとよいでしょう。

12. C#抽象メソッドの理解を深める練習問題

抽象メソッドは、実際にコードを書くことで理解しやすくなります。ここでは、初心者向けの練習問題を紹介します。

12-1. 抽象クラスを作成する練習

まずは、抽象クラスを作る練習です。

次の条件でクラスを作成してみましょう。

Vehicleという抽象クラスを作成します。Moveという抽象メソッドを定義します。

解答例は次のとおりです。

C#
public abstract class Vehicle
{
public abstract void Move();
}

この時点では、Moveメソッドに処理を書きません。抽象メソッドなので、最後はセミコロンで終わります。

12-2. 抽象メソッドをoverrideする練習

次に、Vehicleクラスを継承したCarクラスを作成してみましょう。

C#
using System;

public abstract class Vehicle
{
public abstract void Move();
}

public class Car : Vehicle
{
public override void Move()
{
Console.WriteLine("車が走ります");
}
}

Carクラスでは、Moveメソッドをoverrideして実装しています。

抽象メソッドを実装するときは、必ずoverrideを付けることを意識しましょう。

12-3. 通常メソッドと抽象メソッドを組み合わせる練習

抽象クラスには、通常メソッドと抽象メソッドを一緒に書くことができます。

C#
using System;

public abstract class Vehicle
{
public void Start()
{
Console.WriteLine("エンジンを始動します");
}

public abstract void Move();
}

public class Car : Vehicle
{
public override void Move()
{
Console.WriteLine("車が走ります");
}
}

Startメソッドは共通処理です。Moveメソッドは乗り物によって動き方が異なるため、抽象メソッドにしています。

このように、共通処理は通常メソッド、個別処理は抽象メソッドにすると整理しやすくなります。

12-4. エラーを修正する練習

次のコードにはエラーがあります。

C#
public abstract class Animal
{
public abstract void Speak()
{
Console.WriteLine("鳴きます");
}
}

抽象メソッドに処理本体が書かれているためエラーになります。

正しくは次のように修正します。

C#
public abstract class Animal
{
public abstract void Speak();
}

または、処理を持たせたい場合は抽象メソッドではなく通常メソッドにします。

C#
public class Animal
{
public void Speak()
{
Console.WriteLine("鳴きます");
}
}

このように、抽象メソッドに処理を書いていないか確認することが大切です。

13. C#抽象メソッドに関するよくある質問

最後に、C#の抽象メソッドについて初心者が疑問に思いやすいポイントを解説します。

13-1. 抽象メソッドはprivateにできる?

通常の抽象メソッドはprivateにできません。

理由は、抽象メソッドは派生クラスで実装する必要があるからです。privateにすると、そのクラスの中からしかアクセスできず、派生クラスで実装できません。

次のようなコードはエラーになります。

C#
public abstract class Sample
{
private abstract void Execute();
}

抽象メソッドには、一般的にpublicprotectedを使います。

C#
public abstract class Sample
{
protected abstract void Execute();
}

protectedにすると、派生クラスからアクセスできますが、外部からは直接呼び出せません。

13-2. 抽象メソッドにstaticは付けられる?

抽象クラス内で定義する通常の抽象メソッドには、基本的にstaticは付けません。

抽象メソッドは、派生クラスのインスタンスで実装されることを前提にしています。一方、staticメソッドはインスタンスではなくクラスに属するメソッドです。

初心者のうちは、抽象メソッドは次のようにインスタンスメソッドとして書くと覚えておくとよいです。

C#
public abstract class Sample
{
public abstract void Execute();
}

なお、近年のC#ではインターフェースにおけるstatic abstractメンバーなど、より高度な機能もあります。ただし、抽象クラスの基本を学ぶ段階では、まず「抽象メソッドは派生クラスでoverrideする」と理解するのが重要です。

13-3. 抽象クラスにコンストラクタは書ける?

抽象クラスにもコンストラクタを書くことができます。

C#
using System;

public abstract class Animal
{
public string Name { get; }

public Animal(string name)
{
Name = name;
}

public abstract void Speak();
}

抽象クラス自体はインスタンス化できませんが、派生クラスのインスタンスを作るときに、親クラスのコンストラクタが呼び出されます。

C#
public class Dog : Animal
{
public Dog(string name) : base(name)
{
}

public override void Speak()
{
Console.WriteLine($"{Name}がワンと鳴きます");
}
}

このように、共通の初期化処理を抽象クラスのコンストラクタに書くことができます。

13-4. 抽象メソッドとvirtualはどちらを使うべき?

派生クラスで必ず実装させたい場合は、抽象メソッドを使います。

C#
public abstract void Execute();

親クラスで基本処理を用意し、必要な場合だけ派生クラスで変更したい場合は、virtualメソッドを使います。

C#
public virtual void Execute()
{
Console.WriteLine("基本処理を実行します");
}

判断基準は、親クラス側で標準の処理を書けるかどうかです。

標準の処理を書けない、または必ず子クラスごとに処理を変えたい場合はabstractを使います。

標準の処理があり、一部のクラスだけ変更したい場合はvirtualを使います。

13-5. 初心者はまず何を覚えればよい?

初心者は、まず次の4つを覚えるとよいです。

C#の抽象メソッドは、処理本体を持たないメソッドです。

抽象メソッドは、抽象クラスの中に書きます。

抽象クラスを継承したクラスは、抽象メソッドを必ず実装します。

抽象メソッドを実装するときは、overrideを使います。

特に重要なのは、次の形です。

C#
public abstract class Animal
{
public abstract void Speak();
}

public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}

この基本形を理解できれば、C#の抽象メソッドの土台は十分に身につきます。

まとめ

C#の抽象メソッドは、親クラスでメソッドの形だけを定義し、具体的な処理を派生クラスに任せるための仕組みです。

抽象メソッドを定義するときは、abstractキーワードを使います。抽象メソッドには処理本体を書かず、最後にセミコロンを付けます。また、抽象メソッドは抽象クラスの中で定義する必要があります。

派生クラスでは、overrideキーワードを使って抽象メソッドを実装します。実装を忘れるとコンパイルエラーになるため、必要な処理を強制できる点が大きなメリットです。

通常メソッドは処理を持てますが、抽象メソッドは処理を持てません。virtualメソッドは標準の処理を持ちながら必要に応じて上書きできるため、abstractとは使い分けが必要です。

抽象クラスや抽象メソッドは、共通の設計ルールを作り、コードの拡張性や保守性を高めるために役立ちます。初心者はまず、「abstractで定義し、overrideで実装する」という基本をしっかり覚えておきましょう。