C#入門:継承(Inheritance)とは何か?再利用可能なコードへの第一歩
以下は、C#における継承(Inheritance)について解説する、初学者向けの技術ブログ記事です。クラス設計の基本を学び、再利用性と保守性を高めるコードを書く第一歩としてご活用ください。
1. はじめに
オブジェクト指向プログラミングの重要な概念の1つが「継承」です。C#でも、あるクラス(親クラス・基底クラス)の機能を別のクラス(子クラス・派生クラス)が受け継ぐことができます。
この記事では以下を解説します:
- 継承とは何か
- 基本的な書き方
- メリットと注意点
- 実例コード
- 練習問題
2. 継承とは?
継承(Inheritance)とは、あるクラス(基底クラス)のプロパティやメソッドを、新しいクラス(派生クラス)が「引き継ぐ」仕組みです。
✅ 再利用性が高まり、共通の処理をまとめて管理しやすくなります。
Animalが基本クラス、DogやCatが派生クラス

3. 基本構文
InheritanceSampleプロジェクトとして作成しましょう
class Animal
{
public void Eat()
{
Console.WriteLine("食べています");
}
}
class Dog : Animal
{
public void Bark()
{
Console.WriteLine("ワンワン!");
}
}
上記の例では、DogクラスがAnimalクラスを継承しています。よって、Dogクラスのインスタンスは、Eat()メソッドも利用可能です。

今回のように
- Animal → Dog という 下向きの継承矢印
- 並んでいるクラスの横に、それぞれの絵と動作を描いた構成
は、初学者にとって非常に直感的でわかりやすい図です。
理由:
- 上下関係=階層構造のイメージと一致 →「上が親クラス」「下が子クラス」という物理的なレイアウトは自然に理解されやすいです。
- 矢印で「DogはAnimalの一種」という方向を明示 → Dog は Animal から「機能を受け継ぐ」と直感的に読み取れます。
- 動作の違い(EatとBark)も視覚で表現 → クラスの違いと機能の違いが視覚的に一目瞭然です。
もし変えるとしたら…
- UML的な形式では逆向き(上向き)の矢印 ▲ が使われますが、それは中上級者向けです。
- 初学者には「親→子」の流れのほうが 感覚的にしっくりくる 場合が多いです。
結論:
今回の「下向き矢印」は初学者に最適な表現です。
var dog = new Dog();
dog.Eat(); // → 食べています
dog.Bark(); // → ワンワン!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InheritanceSample
{
internal class Program
{
static void Main(string[] args)
{
var dog = new Dog();
dog.Eat(); // → 食べています
dog.Bark(); // → ワンワン!
}
}
class Animal
{
public void Eat()
{
Console.WriteLine("食べています");
}
}
class Dog : Animal
{
public void Bark()
{
Console.WriteLine("ワンワン!");
}
}
}
4. メリット
✅ コードの再利用
共通機能(例:Eat)は親クラスに1回書けばOK。
✅ 拡張性が高い
新しい動物(例:Cat)を追加しても、共通機能を再利用可能。
✅ 保守性の向上
共通の動作を親クラスだけ修正すれば、すべての子クラスに反映される。
5. overrideとvirtual
親クラスのメソッドを上書きしたい場合は、virtualとoverrideを使います。
InheritanceSampleOverrideプロジェクトとして作成しましょう
class Animal
{
public virtual void Speak()
{
Console.WriteLine("何かを話します");
}
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワンワン!");
}
}
var a = new Animal();
a.Speak(); // → 何かを話します
var d = new Dog();
d.Speak(); // → ワンワン!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InheritanceSampleOverride
{
internal class Program
{
static void Main(string[] args)
{
var a = new Animal();
a.Speak(); // → 何かを話します
var d = new Dog();
d.Speak(); // → ワンワン!
}
}
class Animal
{
public virtual void Speak()
{
Console.WriteLine("何かを話します");
}
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワンワン!");
}
}
}
6. 実践例:Person → Student
InheritanceSamplePersonStudentプロジェクトとして作成しましょう
class Person
{
public string Name { get; set; }
public void Introduce()
{
Console.WriteLine($"私は{Name}です");
}
}
class Student : Person
{
public int Grade { get; set; }
public void ShowGrade()
{
Console.WriteLine($"成績は{Grade}点です");
}
}
var s = new Student { Name = "山田", Grade = 90 };
s.Introduce(); // → 私は山田です
s.ShowGrade(); // → 成績は90点です
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InheritanceSamplePersonStudent
{
internal class Program
{
static void Main(string[] args)
{
var s = new Student { Name = "山田", Grade = 90 };
s.Introduce(); // → 私は山田です
s.ShowGrade(); // → 成績は90点です
}
}
class Person
{
public string Name { get; set; }
public void Introduce()
{
Console.WriteLine($"私は{Name}です");
}
}
class Student : Person
{
public int Grade { get; set; }
public void ShowGrade()
{
Console.WriteLine($"成績は{Grade}点です");
}
}
}
7. 注意点:is-a関係の確認
継承を使うときは、「is-a」関係が成り立つかを確認しましょう。
- ✅ Dog is-a Animal → OK
- ❌ Car(車) is-a Animal → NG → 継承ではなくコンポジションを検討すべき
継承(Inheritance)を使うときに最も大切なのは、「is-a」関係(~は~である)が成り立つかどうかです。
この関係が不自然な場合、継承はかえって設計を複雑にし、意味が崩れてしまいます。
● is-a関係とは?
継承は「あるクラスが別のクラスの一種である」ときに使用すべきです。
✅ 正しい例:
Dog is-a Animal // → OK(犬は動物の一種)
class Animal
{
public void Breathe() => Console.WriteLine("呼吸している");
}
class Dog : Animal
{
public void Bark() => Console.WriteLine("ワンワン!");
}
→ Dog は Animal を継承しても意味が通るし、設計上も自然です。
❌ 不適切な例:Car is-a Engine
Car is-a Engine // → NG(車はエンジンの一種ではない)
- 車(Car) は「エンジン(Engine)」の一種ではありません。
- 「車はエンジンを含んでいる(has-an Engine)」という構成関係が正しいです。
▶ 正しい設計:コンポジション(has-a)
class Engine
{
public void Start() => Console.WriteLine("エンジン始動");
}
class Car
{
private Engine engine = new Engine();
public void StartCar()
{
engine.Start();
Console.WriteLine("車が走り出します");
}
}
- Car は Engine を持っている(has-a)
- このようなときは継承ではなくコンポジションを使いましょう
✅ is-a と has-a の違いまとめ
関係 | 用語 | 例 | 対応設計 |
---|---|---|---|
is-a(~である) | 継承 | Dog is-a Animal | Dog : Animal |
has-a(~を持つ) | コンポジション | Car has-an Engine | CarがEngineをフィールドに持つ |
🚫 よくある誤用に注意!
誤った継承設計 | なぜ問題か |
---|---|
class Car : Engine | 意味的に誤り。「車はエンジンの一種」ではない |
class User : Logger | ログ出力を継承すると、責務が混乱する場合がある。ILoggerなどのインターフェースで切り分けるべき |
🧩 補足:Car is-a Vehicle は正しい
逆に、次のような継承は意味的にも設計的にも自然です。
Car is-a Vehicle // ✅ OK(車は乗り物の一種)
abstract class Vehicle
{
public abstract void Move();
}
class Car : Vehicle
{
public override void Move()
{
Console.WriteLine("車が走行します");
}
}
→ CarはVehicleの一種なので、継承は自然な設計です。
✅ まとめ(is-aを使う前のチェックリスト)
- 「~は~の一種である」と言い換えられるか?
- 継承元のメソッドが子クラスにとって意味を持つか?
- 構成要素(has-a)を誤って継承していないか?
このような「is-a / has-a」の判断力は、オブジェクト指向設計における基礎体力です。継承の便利さに飛びつくのではなく、「意味のある関係か?」を常に問いながら設計していきましょう。
ご希望があれば、この記事全体を図解付きや、PDF出力用として再構成することも可能です。お気軽にお申し付けください。
8. 練習問題
問題:
次のようなVehicleクラスを継承して、Carクラスを作ってみましょう。
class Vehicle
{
public void Run()
{
Console.WriteLine("走行中");
}
}
- Carクラスに「燃料を補給する」メソッドを追加してください
- Carインスタンスで、両方のメソッドを呼び出してください
Vehicleクラスを継承したCarクラスに「燃料を補給する」機能(Refuel()メソッド)を追加し、両方のメソッドを呼び出します。
✅ サンプルコード
using System;
class Vehicle
{
public void Run()
{
Console.WriteLine("走行中");
}
}
class Car : Vehicle
{
public void Refuel()
{
Console.WriteLine("燃料を補給しました");
}
}
class Program
{
static void Main()
{
Car myCar = new Car();
myCar.Run(); // 親クラスのメソッド
myCar.Refuel(); // 子クラスで追加したメソッド
}
}
✅ 実行結果
走行中
燃料を補給しました
✅ 解説
- Car は Vehicle を継承しているので、Run() メソッドを使うことができます。
- Car 独自のメソッド Refuel() を追加し、Main メソッドで両方のメソッドを呼び出しています。
- 継承によって共通機能を使いつつ、派生クラス独自の機能を拡張できる例です。
9. まとめ
- 継承はオブジェクト指向の基本中の基本
- コードの再利用性と保守性を向上させる
- 適切な場面で活用することで、アプリ全体の設計が美しくなる
実務では、継承よりコンポジション(委譲)の方が適切な場合も多いことも学んでいきましょう!
ディスカッション
コメント一覧
まだ、コメントがありません