C# overrideとは?使い方・virtual/abstractとの違い・エラー解決まで初心者向けに解説
はじめに
C#を学び始めると、クラスや継承を扱う場面で override というキーワードが出てきます。
override は、親クラスで定義されたメソッドやプロパティの処理を、子クラス側で上書きして使うための仕組みです。C#のオブジェクト指向プログラミングでは非常に重要な機能であり、virtual や abstract とあわせて理解することで、柔軟で拡張しやすい設計ができるようになります。
一方で、初心者のうちは次のような疑問を持ちやすいポイントでもあります。
「overrideはいつ使うのか」
「virtualやabstractとの違いは何か」
「newやoverloadとは何が違うのか」
「オーバーライドする適切なメソッドが見つかりません、というエラーはどう直すのか」
この記事では、C#の override の意味、基本的な書き方、virtual・abstract・new・overload との違い、よくあるエラーと解決方法まで、初心者向けにわかりやすく解説します。
1. C#のoverrideとは?初心者向けに意味をわかりやすく解説
1-1. overrideは親クラスのメソッドを子クラスで上書きする仕組み
C#の override は、親クラスで定義されたメソッドを、子クラスで別の処理に上書きするためのキーワードです。
たとえば、親クラスに「音を鳴らす」というメソッドがあり、犬クラスでは「ワン」、猫クラスでは「ニャー」と表示したい場合があります。このように、共通のメソッド名を使いながら、クラスごとに異なる処理を実行したいときに override を使います。
C#class Animal
{
public virtual void Speak()
{
Console.WriteLine("動物が鳴きます");
}
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}
この例では、Animal クラスの Speak メソッドを、Dog クラスで override しています。
親クラスでは基本的な動作を定義し、子クラスでは具体的な動作に変更する、というイメージです。
1-2. overrideを使う目的は継承先で処理を変えること
override を使う主な目的は、継承先のクラスで処理内容を変えることです。
継承を使うと、親クラスの機能を子クラスに引き継ぐことができます。しかし、すべての子クラスが親クラスとまったく同じ処理をするとは限りません。
たとえば、次のようなケースがあります。
動物という共通の分類は同じでも、犬と猫では鳴き声が違います。
社員という共通の分類は同じでも、正社員とアルバイトでは給与計算の方法が違います。
キャラクターという共通の分類は同じでも、戦士と魔法使いでは攻撃方法が違います。
このように、「共通の型として扱いたいが、実際の処理はクラスごとに変えたい」という場面で override が役立ちます。
1-3. overrideが使われる代表的な場面
C#で override が使われる代表的な場面は、次のようなケースです。
まず、親クラスで共通のメソッドを用意し、子クラスごとに処理を変えたい場合です。これは最も基本的な使い方です。
C#class Shape
{
public virtual double GetArea()
{
return 0;
}
}
class Circle : Shape
{
public double Radius { get; set; }
public override double GetArea()
{
return Radius * Radius * Math.PI;
}
}
この例では、図形を表す Shape クラスに GetArea メソッドを定義し、円を表す Circle クラスで面積計算の処理を上書きしています。
また、C#では ToString、Equals、GetHashCode など、もともと object クラスに定義されているメソッドを override することもよくあります。
C#class Person
{
public string Name { get; set; }
public override string ToString()
{
return $"名前: {Name}";
}
}
このように、オブジェクトを文字列として表示するときの内容を変更する場面でも override はよく使われます。
1-4. overrideとオブジェクト指向・ポリモーフィズムの関係
override は、オブジェクト指向の重要な考え方であるポリモーフィズムと深く関係しています。
ポリモーフィズムとは、日本語では「多態性」と呼ばれます。簡単に言うと、同じメソッド呼び出しでも、実際のオブジェクトの種類によって異なる処理が実行される仕組みです。
C#Animal animal = new Dog();
animal.Speak();
このコードでは、変数の型は Animal ですが、実際に入っているオブジェクトは Dog です。
Dog クラスで Speak メソッドを override していれば、実行されるのは Animal の Speak ではなく、Dog の Speak です。
つまり、override を使うことで、親クラス型の変数で扱いながら、実際の子クラスに応じた処理を実行できます。
これがC#における override の大きなメリットです。
2. C#でoverrideを使うための基本ルール
2-1. 親クラス側にはvirtual・abstract・overrideのいずれかが必要
C#で override を使うには、親クラス側のメソッドが上書き可能である必要があります。
具体的には、親クラスのメソッドに次のいずれかが付いている必要があります。
C#virtual
abstract
override
たとえば、次のように virtual が付いたメソッドは、子クラスで override できます。
C#class Parent
{
public virtual void Show()
{
Console.WriteLine("親クラスの処理");
}
}
一方で、次のように何も付いていない通常のメソッドは override できません。
C#class Parent
{
public void Show()
{
Console.WriteLine("親クラスの処理");
}
}
このメソッドを子クラスで override しようとすると、コンパイルエラーになります。
2-2. 子クラス側ではoverrideキーワードを付ける
親クラス側で virtual や abstract が付いているメソッドを上書きする場合、子クラス側では override キーワードを付けます。
C#class Child : Parent
{
public override void Show()
{
Console.WriteLine("子クラスの処理");
}
}
override を付けることで、「このメソッドは親クラスのメソッドを上書きしている」という意味になります。
C#では、単に同じ名前のメソッドを書くだけでは正しいオーバーライドにはなりません。明示的に override と書く必要があります。
この明示的な書き方により、開発者が意図せず親クラスのメソッドを上書きしてしまうことを防げます。
2-3. メソッド名・戻り値・引数は基本的に一致させる
override するメソッドは、親クラスのメソッドとシグネチャを一致させる必要があります。
シグネチャとは、主に次の情報の組み合わせです。
メソッド名、引数の数、引数の型、引数の順番です。
また、戻り値の型も基本的に親クラスと一致している必要があります。
C#class Parent
{
public virtual int Calculate(int value)
{
return value;
}
}
class Child : Parent
{
public override int Calculate(int value)
{
return value * 2;
}
}
この例では、メソッド名 Calculate、戻り値 int、引数 int value が一致しているため、正しく override できます。
次のように引数の型が違うと、別のメソッドとして扱われるため、正しいオーバーライドになりません。
C#class Child : Parent
{
public override int Calculate(string value)
{
return 0;
}
}
このようなコードはエラーになります。
2-4. アクセス修飾子は親クラスと整合させる
override する場合、アクセス修飾子も親クラスと整合している必要があります。
たとえば、親クラスのメソッドが public なら、子クラスの override メソッドも通常は public にします。
C#class Parent
{
public virtual void Show()
{
}
}
class Child : Parent
{
public override void Show()
{
}
}
親クラスが protected の場合は、子クラス側も protected override と書きます。
C#class Parent
{
protected virtual void Show()
{
}
}
class Child : Parent
{
protected override void Show()
{
}
}
親クラスよりもアクセス範囲を勝手に狭めたり広げたりすると、エラーになることがあります。
2-5. staticメソッドはoverrideできない
C#では、static メソッドを override することはできません。
override は、インスタンスに対して動的に呼び出されるメソッドを上書きする仕組みです。一方、static メソッドはクラスそのものに属するメソッドであり、インスタンスに紐づきません。
そのため、次のようなコードはエラーになります。
C#class Parent
{
public static void Show()
{
}
}
class Child : Parent
{
public override static void Show()
{
}
}
static メソッドで同じ名前の処理を用意したい場合は、override ではなく、別の設計を検討する必要があります。
3. C# overrideの基本的な書き方とサンプルコード
3-1. virtualメソッドをoverrideする基本例
C#で override を使う最も基本的なパターンは、親クラスに virtual メソッドを用意し、子クラスで override する形です。
C#using System;
class Animal
{
public virtual void Speak()
{
Console.WriteLine("動物が鳴きます");
}
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("犬がワンと鳴きます");
}
}
class Program
{
static void Main()
{
Dog dog = new Dog();
dog.Speak();
}
}
実行結果は次のようになります。
C#犬がワンと鳴きます
親クラスの Speak メソッドには virtual が付いています。これにより、子クラスで上書き可能になります。
子クラスの Dog では、override を使って Speak メソッドの処理を変更しています。
3-2. 親クラスの処理を子クラスで変更する例
次に、親クラスでは基本的な料金計算を行い、子クラスでは割引を適用する例を見てみましょう。
C#using System;
class Order
{
public virtual int GetTotalPrice()
{
return 1000;
}
}
class DiscountOrder : Order
{
public override int GetTotalPrice()
{
return 800;
}
}
class Program
{
static void Main()
{
Order normalOrder = new Order();
Order discountOrder = new DiscountOrder();
Console.WriteLine(normalOrder.GetTotalPrice());
Console.WriteLine(discountOrder.GetTotalPrice());
}
}
実行結果は次のようになります。
C#1000
800
注目すべき点は、discountOrder の変数の型が Order であるにもかかわらず、実際には DiscountOrder の GetTotalPrice が呼び出されることです。
これが override によるポリモーフィズムです。
3-3. baseキーワードで親クラスの処理も呼び出す方法
子クラスで override した場合でも、親クラスの処理を完全に捨てる必要はありません。
base キーワードを使うと、親クラスのメソッドを呼び出せます。
C#using System;
class User
{
public virtual void ShowProfile()
{
Console.WriteLine("ユーザー情報を表示します");
}
}
class AdminUser : User
{
public override void ShowProfile()
{
base.ShowProfile();
Console.WriteLine("管理者権限を表示します");
}
}
class Program
{
static void Main()
{
AdminUser admin = new AdminUser();
admin.ShowProfile();
}
}
実行結果は次のようになります。
C#ユーザー情報を表示します
管理者権限を表示します
base.ShowProfile() によって、親クラスの ShowProfile メソッドを呼び出しています。
親クラスの共通処理を実行したうえで、子クラス独自の処理を追加したい場合に便利です。
3-4. 複数の子クラスでoverrideする実践例
override は、複数の子クラスでそれぞれ異なる処理を実装する場面で特に効果を発揮します。
C#using System;
using System.Collections.Generic;
class Character
{
public virtual void Attack()
{
Console.WriteLine("通常攻撃をします");
}
}
class Warrior : Character
{
public override void Attack()
{
Console.WriteLine("剣で攻撃します");
}
}
class Mage : Character
{
public override void Attack()
{
Console.WriteLine("魔法で攻撃します");
}
}
class Archer : Character
{
public override void Attack()
{
Console.WriteLine("弓で攻撃します");
}
}
class Program
{
static void Main()
{
List<Character> characters = new List<Character>
{
new Warrior(),
new Mage(),
new Archer()
};
foreach (Character character in characters)
{
character.Attack();
}
}
}
実行結果は次のようになります。
C#剣で攻撃します
魔法で攻撃します
弓で攻撃します
すべて Character 型として扱っていますが、実際に呼び出される Attack メソッドは各子クラスのものです。
このように、override を使うと、共通の型でまとめて扱いながら、個別の動作を実現できます。
4. overrideとvirtualの違い
4-1. virtualは「上書きされる側」に付けるキーワード
virtual は、親クラス側のメソッドに付けるキーワードです。
意味としては、「このメソッドは子クラスで上書きできます」という宣言です。
C#class Parent
{
public virtual void Show()
{
Console.WriteLine("親クラスのShow");
}
}
virtual が付いたメソッドは、子クラスで必要に応じて override できます。
つまり、virtual は上書きされる準備をするためのキーワードです。
4-2. overrideは「上書きする側」に付けるキーワード
override は、子クラス側のメソッドに付けるキーワードです。
意味としては、「親クラスの上書き可能なメソッドを、このクラスで再定義します」という宣言です。
C#class Child : Parent
{
public override void Show()
{
Console.WriteLine("子クラスのShow");
}
}
親クラスの virtual メソッドを、子クラスで override するという関係になります。
整理すると、virtual は親クラス側、override は子クラス側で使います。
4-3. virtualなしのメソッドをoverrideできない理由
C#では、親クラスの通常メソッドを子クラスで勝手に override することはできません。
理由は、親クラスの設計者が「このメソッドは上書きされることを想定している」と明示していないからです。
たとえば、次のコードはエラーになります。
C#class Parent
{
public void Show()
{
Console.WriteLine("親クラスのShow");
}
}
class Child : Parent
{
public override void Show()
{
Console.WriteLine("子クラスのShow");
}
}
親クラスの Show に virtual が付いていないため、子クラスで override できません。
これは、意図しない上書きによるバグを防ぐための仕組みです。
4-4. virtualとoverrideをセットで使う基本パターン
virtual と override は、次のようにセットで使うのが基本です。
C#class Parent
{
public virtual void Method()
{
Console.WriteLine("親クラスの処理");
}
}
class Child : Parent
{
public override void Method()
{
Console.WriteLine("子クラスの処理");
}
}
親クラスで virtual、子クラスで override という形を覚えておくと、基本的な使い方は理解しやすくなります。
ただし、親クラス側が abstract の場合も、子クラス側では override を使います。
5. overrideとabstractの違い
5-1. abstractは処理内容を持たない抽象メソッド
abstract は、処理内容を持たないメソッドを定義するためのキーワードです。
C#abstract class Animal
{
public abstract void Speak();
}
この例では、Speak メソッドに処理本体がありません。
abstract メソッドは、「このメソッドは必要だが、具体的な処理は子クラスで決めてください」という意味になります。
なお、abstract メソッドを持つクラスは、必ず abstract class として定義する必要があります。
5-2. abstractメソッドは継承先でoverrideが必須
abstract メソッドは、継承先の具象クラスで必ず override しなければなりません。
C#abstract class Animal
{
public abstract void Speak();
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}
Dog クラスは Animal クラスを継承しているため、Speak メソッドを必ず実装する必要があります。
もし Dog クラスで Speak を override しない場合、Dog クラスも abstract にする必要があります。
5-3. virtualは任意でoverride、abstractは必ずoverride
virtual と abstract の大きな違いは、子クラスでの上書きが任意か必須かです。
virtual メソッドは、親クラス側に処理本体があります。子クラスで必要があれば override しますが、必ずしも上書きする必要はありません。
C#class Animal
{
public virtual void Speak()
{
Console.WriteLine("動物が鳴きます");
}
}
一方、abstract メソッドには処理本体がありません。そのため、具象クラスでは必ず override して処理を実装する必要があります。
C#abstract class Animal
{
public abstract void Speak();
}
つまり、virtual は「上書きしてもよい」、abstract は「必ず上書きしなければならない」と考えるとわかりやすいです。
5-4. abstractクラスとoverrideの使い分け
abstract クラスは、共通の枠組みだけを用意し、具体的な処理を子クラスに任せたい場合に使います。
たとえば、図形の面積を求める処理を考えてみます。
C#abstract class Shape
{
public abstract double GetArea();
}
class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double GetArea()
{
return Width * Height;
}
}
class Circle : Shape
{
public double Radius { get; set; }
public override double GetArea()
{
return Radius * Radius * Math.PI;
}
}
Shape クラスでは、「面積を求める」というメソッドが必要であることだけを定義しています。
具体的な計算方法は、四角形なら Width * Height、円なら Radius * Radius * Math.PI のように異なります。
このように、親クラスで共通のルールを決め、子クラスで具体的な処理を実装したい場合は abstract と override の組み合わせが適しています。
6. override・new・overloadの違い
6-1. overrideは親クラスのメソッドを再定義する
override は、親クラスで定義された上書き可能なメソッドを、子クラスで再定義する仕組みです。
C#class Parent
{
public virtual void Show()
{
Console.WriteLine("Parent");
}
}
class Child : Parent
{
public override void Show()
{
Console.WriteLine("Child");
}
}
この場合、親クラス型の変数に子クラスのインスタンスを入れても、子クラスの Show が呼び出されます。
C#Parent obj = new Child();
obj.Show();
実行結果は次のようになります。
C#Child
これが override の特徴です。
6-2. newは親クラスのメソッドを隠す
new は、親クラスのメソッドを上書きするのではなく、子クラス側で同じ名前のメソッドを新しく定義して、親クラスのメソッドを隠すために使います。
C#class Parent
{
public void Show()
{
Console.WriteLine("Parent");
}
}
class Child : Parent
{
public new void Show()
{
Console.WriteLine("Child");
}
}
この場合、変数の型によって呼び出されるメソッドが変わります。
C#Child child = new Child();
child.Show();
Parent parent = new Child();
parent.Show();
実行結果は次のようになります。
C#Child
Parent
Parent 型の変数から呼び出すと、親クラスの Show が実行されます。
これは override とは大きく異なる点です。
6-3. overloadは同じ名前で引数違いのメソッドを作る
overload、つまりオーバーロードは、同じクラス内に同じ名前で引数が異なるメソッドを複数定義する仕組みです。
C#class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
public int Add(int a, int b, int c)
{
return a + b + c;
}
public double Add(double a, double b)
{
return a + b;
}
}
この例では、すべて Add という名前ですが、引数の数や型が異なります。
override は継承関係における上書きですが、overload は同じ名前のメソッドを引数違いで複数用意する仕組みです。
6-4. overrideとnewを混同しやすいケース
override と new は、どちらも親クラスと子クラスで同じ名前のメソッドを扱うため、混同しやすいです。
違いを理解するには、親クラス型の変数で呼び出したときの動作を見るとわかりやすいです。
C#class Parent
{
public virtual void Show()
{
Console.WriteLine("Parent");
}
}
class OverrideChild : Parent
{
public override void Show()
{
Console.WriteLine("OverrideChild");
}
}
class NewChild : Parent
{
public new void Show()
{
Console.WriteLine("NewChild");
}
}
次のように呼び出してみます。
C#Parent a = new OverrideChild();
Parent b = new NewChild();
a.Show();
b.Show();
実行結果は次のようになります。
C#OverrideChild
Parent
override の場合は、実際のオブジェクトの型に応じて子クラスのメソッドが呼ばれます。
new の場合は、変数の型が Parent であれば親クラスのメソッドが呼ばれます。
6-5. どれを使うべきか判断するポイント
基本的には、親クラスの処理を子クラスで置き換えたい場合は override を使います。
親クラスと子クラスを同じ型として扱い、実際の子クラスに応じた処理を実行したいなら override が適しています。
一方、new は親クラスのメソッドを意図的に隠したい場合に使います。ただし、動作がわかりにくくなるため、初心者のうちは多用しないほうがよいです。
overload は、同じ処理名で引数のパターンを増やしたい場合に使います。継承とは直接関係ありません。
判断の目安は次のとおりです。
親クラスの処理を子クラスで上書きしたいなら override。
親クラスのメソッドを隠して別メソッドとして扱いたいなら new。
同じ名前で引数違いのメソッドを作りたいなら overload。
7. overrideでよくあるエラーと解決方法
7-1. 「オーバーライドする適切なメソッドが見つかりません」の原因
C#で override を使ったときによく出るエラーが、「オーバーライドする適切なメソッドが見つかりません」という内容のエラーです。
これは、子クラスで override と書いているにもかかわらず、親クラス側に対応する上書き可能なメソッドが見つからないときに発生します。
主な原因は次のようなものです。
親クラスのメソッドに virtual や abstract が付いていない。
メソッド名が間違っている。
戻り値の型が一致していない。
引数の型や数が一致していない。
アクセス修飾子が合っていない。
親クラスを正しく継承していない。
このエラーが出た場合は、まず親クラスのメソッド定義と子クラスの override メソッド定義を見比べることが重要です。
7-2. 親メソッドにvirtualやabstractがない場合の対処法
親クラスのメソッドに virtual や abstract が付いていない場合、そのメソッドは override できません。
エラーになる例は次のとおりです。
C#class Parent
{
public void Show()
{
Console.WriteLine("Parent");
}
}
class Child : Parent
{
public override void Show()
{
Console.WriteLine("Child");
}
}
この場合、親クラス側を次のように修正します。
C#class Parent
{
public virtual void Show()
{
Console.WriteLine("Parent");
}
}
class Child : Parent
{
public override void Show()
{
Console.WriteLine("Child");
}
}
親クラスの設計を変更できる場合は、上書きしたいメソッドに virtual を付けます。
ただし、親クラスが外部ライブラリなどで変更できない場合は、override は使えません。その場合は、継承ではなく別の設計を検討します。
7-3. 戻り値・引数・メソッド名が一致していない場合の対処法
override では、親クラスのメソッドと子クラスのメソッド定義を一致させる必要があります。
次のコードは、引数の型が違うためエラーになります。
C#class Parent
{
public virtual void Show(int value)
{
}
}
class Child : Parent
{
public override void Show(string value)
{
}
}
親クラスは int、子クラスは string になっているため、同じメソッドとは見なされません。
修正するには、引数の型を一致させます。
C#class Child : Parent
{
public override void Show(int value)
{
}
}
また、メソッド名のスペルミスにも注意が必要です。
C#public override void Shoow()
{
}
このように一文字違うだけでも、別のメソッドとして扱われます。
エラーが出たときは、メソッド名、戻り値、引数の数、引数の型、引数の順番を確認しましょう。
7-4. アクセス修飾子が一致していない場合の対処法
親クラスと子クラスでアクセス修飾子が合っていない場合もエラーになります。
たとえば、親クラスが public なのに、子クラスで protected にしてしまうと問題になります。
C#class Parent
{
public virtual void Show()
{
}
}
class Child : Parent
{
protected override void Show()
{
}
}
この場合は、親クラスと同じ public に修正します。
C#class Child : Parent
{
public override void Show()
{
}
}
protected virtual のメソッドを上書きするなら、子クラス側も protected override にします。
C#class Parent
{
protected virtual void Show()
{
}
}
class Child : Parent
{
protected override void Show()
{
}
}
アクセス修飾子の不一致は見落としやすいため、エラー時には必ず確認しましょう。
7-5. sealedが付いたメソッドをoverrideできない場合
C#では、sealed override が付いたメソッドをさらに override することはできません。
sealed override は、「このクラスではオーバーライドするが、これ以上の派生クラスでは再オーバーライドを禁止する」という意味です。
C#class A
{
public virtual void Show()
{
}
}
class B : A
{
public sealed override void Show()
{
}
}
class C : B
{
public override void Show()
{
}
}
この場合、C クラスで Show を override しようとするとエラーになります。
B クラスの Show が sealed override になっているためです。
対処法は、再オーバーライドしない設計にすることです。もし自分で B クラスを変更できるなら、sealed を外すこともできますが、設計上の意図をよく確認する必要があります。
7-6. staticメソッドをoverrideしようとした場合
static メソッドは override できません。
次のようなコードはエラーになります。
C#class Parent
{
public static void Show()
{
}
}
class Child : Parent
{
public override static void Show()
{
}
}
override はインスタンスメソッドに対する仕組みです。static メソッドはクラスに属するため、ポリモーフィズムの対象にはなりません。
対処法としては、インスタンスメソッドとして設計し直す方法があります。
C#class Parent
{
public virtual void Show()
{
}
}
class Child : Parent
{
public override void Show()
{
}
}
クラスごとに処理を変えたい場合は、static ではなく、インスタンスメソッドと override を使う設計にするのが基本です。
8. overrideを使うときの注意点とベストプラクティス
8-1. overrideする理由が明確な場合だけ使う
override は便利な機能ですが、何でも上書きすればよいわけではありません。
親クラスの処理を変更する必要がある場合や、子クラスごとに異なる動作を実現したい場合に使うべきです。
理由が曖昧なまま override を多用すると、どのクラスでどの処理が実行されるのか追いにくくなります。
特に大きなプロジェクトでは、継承階層が深くなるほどコードの見通しが悪くなります。
override を使う前に、「本当に継承で表現するべきか」「インターフェースや委譲で表現したほうがよくないか」を考えることが大切です。
8-2. 親クラスの設計を意識してメソッドを定義する
override を正しく使うには、親クラスの設計が重要です。
親クラス側で virtual にするメソッドは、「子クラスで変更される可能性がある処理」に絞るのが基本です。
すべてのメソッドを virtual にしてしまうと、子クラスで自由に上書きできてしまい、予期しない動作につながる可能性があります。
親クラスを設計するときは、次の点を意識しましょう。
どの処理を共通化するのか。
どの処理を子クラスに任せるのか。
上書きされた場合でもクラス全体の整合性が保たれるか。
このように考えることで、安全で使いやすい親クラスを設計できます。
8-3. base呼び出しが必要か確認する
override したメソッド内で base を呼び出すべきかどうかは、親クラスの処理内容によって変わります。
親クラスの処理を完全に置き換えたい場合は、base を呼び出さないことがあります。
C#public override void Show()
{
Console.WriteLine("子クラス独自の処理");
}
一方、親クラスの共通処理を実行したうえで、子クラス独自の処理を追加したい場合は、base を呼び出します。
C#public override void Show()
{
base.Show();
Console.WriteLine("子クラス独自の追加処理");
}
たとえば、初期化処理、ログ出力、状態更新などが親クラスに含まれている場合、base を呼び出さないと不具合につながることがあります。
override するときは、親クラスの処理を確認し、base 呼び出しが必要か判断しましょう。
8-4. sealed overrideで再オーバーライドを禁止する方法
C#では、sealed override を使うことで、それ以上の派生クラスで再オーバーライドできないようにできます。
C#class BaseClass
{
public virtual void Execute()
{
Console.WriteLine("基本処理");
}
}
class MiddleClass : BaseClass
{
public sealed override void Execute()
{
Console.WriteLine("確定した処理");
}
}
この場合、MiddleClass を継承したクラスでは Execute を再度 override できません。
sealed override は、処理内容をこれ以上変更されたくない場合に使います。
たとえば、セキュリティ上重要な処理や、業務ルールとして固定したい処理などでは、再オーバーライドを禁止することで安全性を高められます。
8-5. 可読性を下げない命名と設計のポイント
override を使うときは、メソッド名やクラス設計のわかりやすさも重要です。
親クラスのメソッド名が曖昧だと、子クラスで override したときに何を変更しているのかわかりにくくなります。
たとえば、Process や Execute のような名前は便利ですが、処理内容が広すぎると可読性が下がります。
できるだけ、役割が伝わる名前にしましょう。
C#public virtual decimal CalculateSalary()
{
return 0;
}
このように、給与計算をするメソッドであることが名前からわかれば、子クラスで override したときも意図が明確になります。
また、継承階層を深くしすぎないことも大切です。
親、子、孫、そのさらに子、というように階層が深くなると、どこで何が override されているのか追いにくくなります。
override は便利ですが、設計を複雑にしすぎないように注意しましょう。
9. C# overrideの実践的な活用例
9-1. ToStringメソッドをoverrideする例
C#では、すべてのクラスは最終的に object クラスを継承しています。
object クラスには ToString メソッドが定義されており、これを override することで、オブジェクトを文字列化したときの表示内容を変更できます。
C#using System;
class Product
{
public string Name { get; set; }
public int Price { get; set; }
public override string ToString()
{
return $"{Name} - {Price}円";
}
}
class Program
{
static void Main()
{
Product product = new Product
{
Name = "ノートパソコン",
Price = 120000
};
Console.WriteLine(product);
}
}
実行結果は次のようになります。
C#ノートパソコン - 120000円
ToString を override しない場合、通常はクラス名のような情報が表示されます。
人が見てわかりやすい文字列にしたい場合は、ToString の override が便利です。
9-2. Equalsメソッドをoverrideする例
Equals メソッドを override すると、オブジェクト同士が等しいかどうかの判定方法を変更できます。
たとえば、商品コードが同じなら同じ商品とみなす例を考えます。
C#using System;
class Product
{
public string Code { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
if (obj is Product other)
{
return Code == other.Code;
}
return false;
}
public override int GetHashCode()
{
return Code.GetHashCode();
}
}
class Program
{
static void Main()
{
Product p1 = new Product { Code = "A001", Name = "商品A" };
Product p2 = new Product { Code = "A001", Name = "別名の商品A" };
Console.WriteLine(p1.Equals(p2));
}
}
実行結果は次のようになります。
C#True
この例では、Name が違っていても、Code が同じなら同じ商品と判定しています。
Equals を override する場合は、通常 GetHashCode もあわせて override します。コレクションや辞書で正しく扱うために重要です。
9-3. ゲーム開発でキャラクターごとに動作を変える例
ゲーム開発では、キャラクターごとに攻撃方法や移動方法を変えたい場面がよくあります。
このような場合、override を使うと共通のキャラクター型で扱いながら、個別の動作を実現できます。
C#using System;
abstract class Character
{
public string Name { get; set; }
public abstract void Attack();
}
class Warrior : Character
{
public override void Attack()
{
Console.WriteLine($"{Name}は剣で攻撃した");
}
}
class Wizard : Character
{
public override void Attack()
{
Console.WriteLine($"{Name}は魔法で攻撃した");
}
}
class Program
{
static void Main()
{
Character warrior = new Warrior { Name = "戦士" };
Character wizard = new Wizard { Name = "魔法使い" };
warrior.Attack();
wizard.Attack();
}
}
実行結果は次のようになります。
C#戦士は剣で攻撃した
魔法使いは魔法で攻撃した
Character クラスでは Attack を abstract にして、具体的な攻撃方法は子クラスに任せています。
キャラクターの種類が増えても、新しい子クラスを追加して Attack を override すれば拡張できます。
9-4. 業務アプリで種類ごとに計算処理を変える例
業務アプリでも、種類ごとに計算処理を変える場面があります。
たとえば、社員の給与計算を考えてみます。
C#using System;
abstract class Employee
{
public string Name { get; set; }
public abstract decimal CalculateSalary();
}
class FullTimeEmployee : Employee
{
public decimal MonthlySalary { get; set; }
public override decimal CalculateSalary()
{
return MonthlySalary;
}
}
class PartTimeEmployee : Employee
{
public decimal HourlyWage { get; set; }
public int HoursWorked { get; set; }
public override decimal CalculateSalary()
{
return HourlyWage * HoursWorked;
}
}
class Program
{
static void Main()
{
Employee fullTime = new FullTimeEmployee
{
Name = "田中",
MonthlySalary = 300000
};
Employee partTime = new PartTimeEmployee
{
Name = "佐藤",
HourlyWage = 1200,
HoursWorked = 80
};
Console.WriteLine($"{fullTime.Name}: {fullTime.CalculateSalary()}円");
Console.WriteLine($"{partTime.Name}: {partTime.CalculateSalary()}円");
}
}
実行結果は次のようになります。
C#田中: 300000円
佐藤: 96000円
正社員とアルバイトでは給与計算の方法が異なりますが、どちらも Employee 型として扱えます。
このように、業務ルールが種類ごとに異なる場合にも override は有効です。
10. C# overrideに関するよくある質問
10-1. overrideとvirtualは必ずセットで使う?
基本的な使い方では、親クラス側に virtual、子クラス側に override を使います。
ただし、親クラス側は必ずしも virtual だけとは限りません。
abstract メソッドを子クラスで実装する場合も override を使います。
また、すでに override されたメソッドを、さらに派生クラスで override することもできます。
C#class A
{
public virtual void Show()
{
}
}
class B : A
{
public override void Show()
{
}
}
class C : B
{
public override void Show()
{
}
}
つまり、子クラス側では override を使いますが、親クラス側は virtual、abstract、または override のいずれかである必要があります。
10-2. privateメソッドはoverrideできる?
private メソッドは override できません。
private メソッドは、そのクラスの内部からしかアクセスできないメソッドです。子クラスからも直接アクセスできないため、オーバーライドの対象にはなりません。
子クラスで上書きしたい場合は、親クラス側のメソッドを protected virtual や public virtual にする必要があります。
C#class Parent
{
protected virtual void Show()
{
}
}
class Child : Parent
{
protected override void Show()
{
}
}
外部には公開したくないが子クラスでは上書きさせたい場合は、protected virtual を使うとよいでしょう。
10-3. コンストラクタはoverrideできる?
C#では、コンストラクタを override することはできません。
コンストラクタはクラスのインスタンスを生成するときに呼び出される特別なメンバーであり、通常のメソッドとは扱いが異なります。
親クラスのコンストラクタを呼び出したい場合は、base を使います。
C#class Parent
{
public Parent(string name)
{
Console.WriteLine(name);
}
}
class Child : Parent
{
public Child(string name) : base(name)
{
Console.WriteLine("Childのコンストラクタ");
}
}
このように、コンストラクタは override するのではなく、base を使って親クラスのコンストラクタを呼び出します。
10-4. インターフェース実装にoverrideは必要?
通常、インターフェースを実装するときに override は使いません。
C#interface ILogger
{
void Log(string message);
}
class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
この場合、Log メソッドはインターフェースの実装であり、親クラスのメソッドを上書きしているわけではありません。
そのため、override は不要です。
ただし、親クラスでインターフェースを実装しており、その実装メソッドが virtual になっている場合は、子クラスで override できることがあります。
C#interface ILogger
{
void Log(string message);
}
class BaseLogger : ILogger
{
public virtual void Log(string message)
{
Console.WriteLine(message);
}
}
class FileLogger : BaseLogger
{
public override void Log(string message)
{
Console.WriteLine($"ファイルに記録: {message}");
}
}
この場合は、インターフェースそのものではなく、親クラスの virtual メソッドを override しています。
10-5. overrideとポリモーフィズムは何が関係している?
override は、C#でポリモーフィズムを実現するための重要な仕組みです。
ポリモーフィズムとは、同じ型として扱っていても、実際のオブジェクトの種類に応じて異なる処理が実行されることです。
C#Animal animal = new Dog();
animal.Speak();
このとき、Dog クラスで Speak を override していれば、Animal 型の変数から呼び出しても Dog の処理が実行されます。
これにより、呼び出し側のコードは具体的な子クラスを意識せずに済みます。
たとえば、犬、猫、鳥など複数のクラスがあっても、すべて Animal 型として扱い、Speak を呼び出すだけで、それぞれに合った処理を実行できます。
この柔軟性が、override とポリモーフィズムの大きなメリットです。
まとめ
C#の override は、親クラスで定義されたメソッドを子クラスで上書きするためのキーワードです。
親クラス側には virtual、abstract、または override が必要で、子クラス側では override を付けてメソッドを再定義します。
virtual は「子クラスで上書きしてもよいメソッド」、abstract は「子クラスで必ず実装すべきメソッド」、override は「親クラスのメソッドを子クラスで上書きするキーワード」です。
また、new は親クラスのメソッドを隠す仕組み、overload は同じ名前で引数違いのメソッドを定義する仕組みであり、override とは目的が異なります。
override を使うことで、親クラス型でまとめて扱いながら、実際の子クラスに応じた処理を実行できます。これはC#のオブジェクト指向プログラミングやポリモーフィズムを理解するうえで非常に重要です。
エラーが出た場合は、親クラスのメソッドに virtual や abstract が付いているか、メソッド名・戻り値・引数・アクセス修飾子が一致しているかを確認しましょう。
C#で継承を使った設計を行うなら、override は避けて通れない基本機能です。まずは virtual と override の基本パターンから理解し、必要に応じて abstract、new、sealed override との違いも押さえていきましょう。

