C#を学習すると必ず出てくるのが、オブジェクト指向!
悩んでる人オブジェクト指向って何?
オブジェクト指向は、C#開発において非常に重要な考え方なんです。
C#は、オブジェクト指向をベースとしたプログラミング言語なので、オブジェクト指向の理解はとても重要です。
本記事では、C#のオブジェクト指向について、イメージ図付きでわかりやすく解説します。
- C#のオブジェクト指向とは何か?
- クラスとインスタンスとオブジェクトの違い
- オブジェクト指向を使うメリット
- カプセル化、継承、ポリモーフィズムの基本


- システムエンジニア10年目
- 会社員3年⇒フリーランス7年目
- 保険系 / 物流系 / 鉄道系 / 小売系などのシステム開発に従事
- プログラミングサポーター3年目
- IT学習サポート実績:100名以上
【C#】オブジェクト指向とは


オブジェクト指向とは、プログラムで扱うデータや処理をオブジェクトという単位で整理しながらプログラム全体を組み立てていく考え方です!
C#では、オブジェクト指向が採用されています。



データや処理をオブジェクト単位で整理するって何?
ピンときませんよね。順番に説明していきますね!
オブジェクト指向が生まれた理由とは
オブジェクト指向が登場する前は、手続き型が主流でした。
プログラムに処理させたい順番に焦点を当てて全体を組み立てていく考え方です。
プログラムは上から順番に処理を実行するので、コンピュータが実行する順にプログラムを組み立てていきます。
次のコード例であれば、処理1⇒処理2⇒処理3の順で実行していきます。
static void Main(string[] args)
{
//処理1:英語でこんにちはを出力
Console.WriteLine("Hello, World!");
//処理2:日本語でこんにちはを出力
Console.WriteLine("こんにちは");
//処理3:スペイン語でこんにちはを出力
Console.WriteLine("Buenos dias!!");
}Hello, World!
こんにちは
Buenos dias!!
手続き型は、基本的な考え方です。
しかし、手続き型だけでは現実的に困る場面が増えてきたため、オブジェクト指向という考え方が生まれました。



手続き型で困る場面って何だろう?
- データと処理がバラバラであること
- データ(変数)と処理(関数)が分離しているので、プログラムが大きくなるほど「どの関数がどのデータを使っているのか」が追いにくくなります。
- 意図しないデータ上書きというバグが頻発したこと
- 処理間でデータを共有するため、グローバル変数を使いがちになり、「どこかで意図せず値が書き変わる」バグが頻発しました。
- コードの再利用が難しいこと
- 似たようなデータ構造があっても、うまく共通化する手段がなく、コピペが横行しました。
これは、実際のシステム開発を経験しないと難しい感覚ですね
手続き型が抱えていた問題点をイメージするため、オブジェクト指向との違いを説明します。
手続き型とオブジェクト指向の違いとは
極端に言うと、違いはクラスの有無です。



クラスって何だろう?
クラスはデータと処理をひとまとめにする仕組みと考えてください。
手続き型では、データと処理はバラバラに管理されています。
以下の例では、部署名や経歴のデータと、更新処理が別々に存在していて、メイン処理から更新処理を実行しています。


一方で、オブジェクト指向の場合は、データと処理をクラス単位でまとめるため、意味のある集まりとして管理することができます。
以下の例では、社員のデータと更新処理が、クラスという枠にまとめられています。





オブジェクト指向は、データと処理をオブジェクト単位でまとめないの?クラス単位なの?
めちゃくちゃ良い疑問です
クラスとオブジェクトの違いについて、これから説明しますね。
クラスとオブジェクトの違いとは
簡単に言えば、クラスはデータ型で、オブジェクトは具体値です。
以下のコード例のように、stringやintはデータ型で、「ジョン」や「27」は具体値です。
クラスとオブジェクトも、これと同じ関係なんです!!
static void Main(string[] args)
{
//データ型:string 、具体値:ジョン
string fullName = "ジョン";
//データ型:int 、具体値:27
int currentAge = 27;
}つまり、オブジェクトを生成するとは、クラスをデータ型として変数宣言し、変数に具体的な情報を設定することです。
たい焼きを例にすると、「たい」の形をした専用の金属型がクラスで、オブジェクトは実際に食べられるたい焼きを指すイメージです。
以下の例では、社員クラスをデータ型として、2つの変数を宣言して、それぞれAさんとBさんの社員情報を設定するということになります。


Aさん、Bさんのオブジェクトは同じデータ型であっても、設定されているデータが違うということです。
色々と説明しましたが、ここで一度整理しましょう!
- プログラムで扱う
データと処理を関連する集まりとして整理する考え方のこと - クラスは、
データと処理をまとめて扱えるデータ型として新たに作成する - オブジェクトは、クラスをデータ型として変数宣言し、具体的なデータをセットしたもの
オブジェクト指向は、関連するデータと処理をオブジェクト単位または、クラス単位でまとめることを前提とした考え方といえます。



ややこしいですね。
オブジェクト指向は思想なので、どうしても説明が曖昧になってしまいます。
プログラムで処理する場合は、オブジェクト単位で操作するため、データと処理はオブジェクト単位でまとめられていると表現できます。
そして、オブジェクトを扱う事前準備として、データを保持する変数とデータを操作する処理をまとめるクラスを定義する必要があるので、クラス単位でまとめる考え方と呼ぶこともできます。
オブジェクト指向は、C#に限らず、JavaやRubyなど様々なプログラミング言語で採用されています。
【C#】オブジェクト指向を理解するために必要な用語


C#開発でオブジェクト指向を理解するために、次の5つの用語を押さえましょう。
| 用語 | 一言で言うと |
|---|---|
| クラス | 自由にカスタマイズできるデータ型、基本テンプレート |
| インスタンス | クラスから作った実体(オブジェクトの一種) |
| オブジェクト | プログラムの中で扱うもの全て |
| コンストラクタ | インスタンス化の時だけ実行される特殊なメソッド |
| メンバー | クラスの中に定義された変数やメソッドの総称 |
クラスとメンバーについて
クラスは、自由にカスタマイズできるデータ型であり、データの形と関連する処理をまとめたテンプレートになります。
データ型には、string型やint型などがあり、以下のコード例のように、データ型に応じた変数を宣言できます。
// メイン処理
static void Main(string[] args)
{
// 変数の宣言と初期化
string name = "マイケル";
int age = 26;
}同様に、クラスもデータ型の一つなので、クラス型の変数を宣言できるのです。
クラスは、関連するデータと処理をまとめる形でカスタマイズします。
オブジェクト指向によるプログラムを実現するため、クラスは必要不可欠といっても過言ではありません。
以下は、社員情報に関連するデータと処理をまとめたクラスの例です。
クラスはこんなイメージで作成します!
// 社員クラス
public class Employee()
{
//***************************************
// データ(フィールドとも呼ぶ)
//***************************************
public string _EmployeeId; //社員ID
public string _EmployeeName; //社員名
public string _CurrentDepartmentName; //部署名
//***************************************
// 処理(メソッドとも呼ぶ)
//***************************************
//部署更新
public void UpdateDepartment(string NewDepartmentName)
{
//現在の部署名を新しい部署名で更新する
this._CurrentDepartmentName = NewDepartmentName;
}
}クラスにまとめられたデータと処理のことを、それぞれ「フィールド」と「メソッド」と呼び、フィールドとメソッドを合わせて、「メンバ」と呼びます。
これは、知識として頭の片隅に入れておく程度でオッケーです🎶
あくまでも、クラスはデータ型の定義をするだけ!!
クラスの内容を使うには、インスタンス化する必要があります。



インスタンス化って、何だろう?
インスタンス化とは、クラス定義を元に、具体的なデータを生成する操作のことで、具体的なデータのことをインスタンスと呼びます。
つまり、クラスはデータ型で、インスタンスは具体的なデータを指します。



具体的なデータはオブジェクトって聞いた気がするけど、インスタンスで正しいのかな?
いい疑問です。ややこしいですよね。
まずは、インスタンスとオブジェクトの違いについて、整理しておきましょう!
インスタンスとオブジェクトの違いとは
インスタンスは、オブジェクトの一つで、クラスから生成したオブジェクトを指します。
言葉の意味としては、オブジェクトがインスタンスよりも広義的に扱われますね。


正直、実務では、オブジェクトとインスタンスを使い分けている人はいない印象です。
チームメンバーとやり取りする際は、オブジェクト≒インスタンスとして、会話しても問題はないです。
クラスとインスタンスの関係について、もう少し説明しますね
クラスとインスタンスの関係とは



クラスとインスタンスって、何がどう違うの?
クラスとインスタンスの関係は、「設計図」と「実際に作られたモノ」の関係です。
もちろん、データ型と具体的なデータの関係といっても問題ないです。
また、オブジェクトとインスタンスは、ほとんど同じ意味で使われるため、「クラスとインスタンスの関係」は、「クラスとオブジェクトの関係」と同じことが言えます。
車を例にすると、クラスが「車の設計図」、インスタンスが「実際の車」にあたります。
車の例で実際のコード例を紹介しますね!
クラス(設計図)の定義はこんな感じです
// 車クラス
class Car
{
//***************************************
// データ
//***************************************
public string _Name; //車の名前
public string _Color; //車体の色
//***************************************
// 処理
//***************************************
//コンストラクタ
public void Car(string inputName, string inputColor)
{
_Name = inputName;
_Color = inputColor;
}
public void Run()
{
Console.WriteLine($"{Name}が走ります");
}
}インスタンス化はこんな感じです。
// メイン処理
static void Main(string[] args)
{
// クラス型で変数宣言(Carクラスの変数を3つ用意)
Car car1;
Car car2;
Car car3;
// インスタンス化して変数に代入
Car car1= new Car("プリウス","白");
Car car2= new Car("クラウン","黒");
Car car3= new Car("カローラ","赤");
}インスタンス化とは、new Car("プリウス","白")などのことで、具体的なデータを生成します。
インスタンス化したら変数へ代入しています。


車の設計図があっても、設計図だけでは車とは言えません。
車は、設計図をもとに製造されて、はじめてプログラムが扱える存在として認識できます。
ここでポイントは、1つのクラスから複数のインスタンスを作れること!!
クラスとインスタンスの違いは、オブジェクト指向の第一歩です!ここをしっかり理解するだけで、その後の学習がグッとラクになりますよ!



インスタンス化は分かったけど、書き方はnew Car("プリウス","白")でいいの?new Car()は違うの?
いい疑問です!
実は、コンストラクタという仕組みが関係しているので、コンストラクタについて説明しますね。
コンストラクタとは
コンストラクタとは、インスタンス化するタイミングに一度だけ実行される特殊なメソッドです。
コンストラクタは基本的に無くてもエラーにはなりません。
しかし、コンストラクタの有無によって、インスタンス化する時の手間が違ってきます。
コンストラクタ無しのインスタンス化
// メイン処理
static void Main(string[] args)
{
// クラス型で変数宣言(Carクラスの変数を3つ用意)
Car car1;
// インスタンス化して変数に代入
Car car1= new Car();
// インスタンスの各データを更新
car1._Name = "プリウス";
car1._Color = "白";
}コンストラクタが無い場合は、インスタンス化した後、_Nameと_Colorへの代入文を別で書く必要が!
一方で、コンストラクタがある場合は、インスタンス化する時、同時に_Nameと_Colorへの代入も実行できます。
コンストラクタ有りのインスタンス化
// メイン処理
static void Main(string[] args)
{
// クラス型で変数宣言(Carクラスの変数を3つ用意)
Car car1;
// インスタンス化して変数に代入
Car car1= new Car("プリウス","白");
}以下のコード例のように、コンストラクタを追加する場合は、クラス名と同じ名前とすることがポイントです。
new Car("プリウス","白")の実行時、コンストラクタが実行されて、_Nameと_Colorへの代入が実施されます。
コンストラクタの記載例
// 車クラス
class Car
{
public string _Name; //車の名前
public string _Color; //車体の色
//コンストラクタ(クラス名と同じ名前のメソッド)
public void Car(string inputName, string inputColor)
{
_Name = inputName;
_Color = inputColor;
}
}コンストラクタがあれば、_Nameと_Colorへの代入が実施されるわけではありません。
あくまでも、コンストラクタの処理に_Nameと_Colorへの代入処理を書いているから実行されています。
代入文を書かなかった場合は、インスタンス化する時に_Nameと_Colorへのデータ設定はされません。



ところで、インスタンスとオブジェクトって同じものなのかな?
似ているので、ややこしいですよね!
今までの内容を振り返ると、次の5つの用語を整理できれば、オブジェクト指向によるC#プログラミングがかなり分かるようになりますよ。
| 用語 | 一言で言うと |
|---|---|
| クラス | 自由にカスタマイズできるデータ型、基本テンプレート。 |
| インスタンス | クラスから作った実体(オブジェクトの一種) |
| オブジェクト | プログラムの中で扱うもの全て |
| コンストラクタ | インスタンス化の時だけ実行される特殊なメソッド |
| メンバー | クラスの中に定義された変数やメソッドの総称 |
【C#】オブジェクト指向を使う3つのメリット


オブジェクト指向を使うメリットは、次の3つです。


- プログラムを整理しやすくなる
- 関連するデータと処理をクラスにまとめられる
- 処理を再利用しやすくなる
- 1つのクラスから複数のインスタンスを作って使い回せる
- 修正や変更に対応しやすくなる
- 修正箇所をクラス内に限定できる
メリット:プログラムを整理しやすくなる
関連するデータと処理をクラスにまとめることで、コードの見通しがよくなります。
例えば、会員情報を管理するプログラムの場合、会員ID・名前・メールアドレスなどのデータをバラバラの変数で管理せず、Memberクラスとしてひとまとめにできます。
プログラムが大きくなっても、どこに何があるのかが一目で分かるようになります。



バラバラに変数を作っても動くし、クラスにまとめる必要ってあるの?
小さなプログラムでは分かりにくいですが、変数が100個・1000個と増えると一気に管理が大変になります!
メリット:処理を再利用しやすくなる
1つのクラスを作っておけば、何度でもインスタンスを作ることができます。
会員管理であれば、Memberクラスのインスタンスを人数分作るだけで、同じデータ構造・同じ処理が何人分でも使い回せます。
毎回ゼロから変数や処理を書き直す必要がなくなるため、開発効率が大幅に上がります。
メリット:修正や変更に対応しやすくなる
オブジェクト指向を使うと、修正する場所をクラスの中に限定できます。
たとえば、会員情報の表示方法を変えたい場合、Memberクラスの中だけを修正すれば済みます。
プログラム全体に処理が散らばっていると、修正箇所を探すだけでも一苦労です。
プログラムは作って終わりではありません!あとから修正することも多いので、整理しやすい形で作ることが大切です!
オブジェクト指向の4つの基本原則


C#のオブジェクト指向には、次の4つの重要な考え方があります。
| 原則 | 一言で言うと |
|---|---|
| 抽象化 | 必要な情報だけに注目して整理すること |
| カプセル化 | データを外部から守り、安全に扱う仕組み |
| 継承 | 既存クラスの機能を引き継いで新しいクラスを作る仕組み |
| ポリモーフィズム | 同じ命令でも、クラスによって動きが変わる仕組み |
Microsoftの公式ドキュメントでも、この4つがC#のオブジェクト指向の基本原則として紹介されています。
Microsoft公式サイトはコチラ
それぞれ紹介しますね!
原則1:抽象化とは?
抽象化とは、プログラムで扱うために必要な情報だけに絞って整理することです。
オブジェクト指向では、現実世界のものシステム上に置き換えますが、置き換えるときに抽象化を考えます。
実際の車の場合、エンジン・タイヤ・ブレーキ・ライト・ハンドルなど、無数の情報があります。
しかし、プログラムで「走る・止まる」だけを表現したいなら、すべての情報は必要ありません。
つまり、現実世界のものは、様々な情報を持っていますが、クラスとして定義する際は、システムで扱う情報だけに絞ることが抽象化です。
車の「名前・色・速度・走る・止まる」という必要最小限の情報だけをクラスとして定義する、これが抽象化。
プログラムの目的に合わせて「何を表現するか」を絞ることで、シンプルで分かりやすいコードが書けるようになります。
抽象化は「余計なものを削ぎ落とす」作業です。最初から完璧にやろうとせず、まず動くものを作りながら少しずつ整理していく感覚で大丈夫ですよ!
原則2:カプセル化とは?
カプセル化とは、データを外部から直接変更されないようにして、安全に扱う考え方です。
銀行口座を例にカプセル化を説明していきますね。
例えば、銀行口座クラスを、以下のように定義したとします。
// 銀行口座クラス
class BankAccount
{
// 口座名義
public string AccountName { get; set; }
// 残高
public int balance;
// コンストラクター
public BankAccount(string accountName, int initialBalance)
{
AccountName = accountName;
balance = initialBalance;
}
}残高を管理するフィールドbalanceのアクセス修飾子には、publicが指定されているので、以下のコード例ように、簡単に-1000円を設定できてしまいます。
これは、システムとしては非常にマズイ状態です。
// メイン処理
static void Main(string[] args)
{
BankAccount account = new BankAccount("田中", 10000);
//簡単に-1000円を設定できてしまう。
// balanceは口座の残高をセットするフィールドなので、簡単にマイナスを設定できるのはマズイ
account.balance = -1000;
}一方で、以下のように、フィールドbalanceのアクセス修飾子をpublic⇒privateにすれば、外部から直接マイナス値を設定できなくなります。
外部から直接設定できない代わりに、メソッドのDeposit()やWithdraw()を用意し、メソッドのみで設定できるようにします。
// 銀行口座クラス
class BankAccount
{
// 口座名義
public string AccountName { get; set; }
// 残高
// 外部から直接変更されないように private にする
private int balance;
// コンストラクター
public BankAccount(string accountName, int initialBalance)
{
AccountName = accountName;
balance = initialBalance;
}
// 入金する
public void Deposit(int amount)
{
if (amount <= 0)
{
Console.WriteLine("入金額は1円以上を指定してください。");
return;
}
balance += amount;
Console.WriteLine($"{amount}円を入金しました。");
}
// 出金する
public void Withdraw(int amount)
{
if (amount <= 0)
{
Console.WriteLine("出金額は1円以上を指定してください。");
return;
}
if (amount > balance)
{
Console.WriteLine("残高不足のため、出金できません。");
return;
}
balance -= amount;
Console.WriteLine($"{amount}円を出金しました。");
}
// 残高を表示する
public void ShowBalance()
{
Console.WriteLine($"{AccountName}さんの残高は{balance}円です。");
}
}さらに、Deposit()やWithdraw()の処理内で、マイナス値が指定されたらエラーとするようにチェックすることで、不正な操作や想定外のバグを防ぐことができます。
// メイン処理
static void Main(string[] args)
{
BankAccount account = new BankAccount("田中", 10000);
account.ShowBalance();
account.Deposit(5000);
account.ShowBalance();
account.Withdraw(3000);
account.ShowBalance();
account.Withdraw(20000);
account.ShowBalance();
}つまり、カプセル化とは、フィールドをprivateにして直接編集できないようにする代わり、編集専用のメソッドを介して、間接的にフィールドを更新できるようにすることです。
ちなみに、専用メソッドのことをアクセサと呼び、アクセサの機能を持ったフィールドのことをプロパティと呼びます。
カプセル化は、アクセサやプロパティを使うことで実現させることができます。
外部から自由にデータを変更できると「残高にマイナス値が入る」「ありえない値がセットされる」といったバグが発生しやすくなるからです。
カプセル化はデータに鍵をかけて守るイメージ。
プロの現場では、むやみにpublicを使わず、必要な部分だけを外部に公開するのが基本的なマナーです。
カプセル化を使うと「おかしな値が外から直接代入される」というバグを防げます!
原則3:継承とは?
継承とは、既存のクラスをもとに新しいクラスを作る仕組みです。
共通する処理を親クラスとしてまとめ、子クラスでそれを引き継げます。
例えば、動物クラスを親クラスとして、犬クラスと猫クラスと鳥クラスをそれぞれ子クラスとして派生できます。


動物クラスを継承して、犬クラスを作るには、class Dog : Animalのように書きます。
// 動物クラス
class Animal
{
public string Name;
public void Eat() { Console.WriteLine($"{Name}がごはんを食べます"); }
}
// 犬クラス
// (Animalを継承。動物クラスのEatメソッドをそのまま使える)
class Dog : Animal
{
public void Bark() { Console.WriteLine($"{Name}が吠えます"); }
}継承は「親の財産を引き継ぐ」イメージです!
共通する処理を何度も書かなくてよくなるので、コードの量が減って管理もしやすくなりますよ!
原則4:ポリモーフィズム
ポリモーフィズムとは、同じメソッド名でも、クラスによって実行される処理が変わる仕組みです。
ポリもーフィズムは、多態性とも言います
virtual と override を使って、子クラスごとに処理を上書きできます。
class Animal {
public virtual void Speak() {
Console.WriteLine("鳴きます");
}
}
class Dog : Animal {
public override void Speak() {
Console.WriteLine("ワン!");
}
}
class Cat : Animal {
public override void Speak() {
Console.WriteLine("ニャー!");
}
}同じSpeak()という命令を出しているだけで、それぞれのクラスに応じた処理が自動的に実行されます。
プログラムに後から新しい動物クラスを追加しても、既存のコードを変更せずに対応できるのが大きな強みです。
「同じ命令でも、相手によって動きが変わる」仕組みです!最初は難しく感じるかもしれませんが、継承を理解したあとに学ぶとスムーズに理解できますよ!
C#のオブジェクト指向を学ぶ順番


オブジェクト指向は、次の順番で学ぶのがおすすめです。
いきなり継承やポリモーフィズムから入ると難しく感じやすいので、基礎からひとつずつ積み上げていきましょう。
クラスとインスタンスを理解する
すべての土台になる概念。ここを飛ばすと後で必ずつまずきます。
毎日使う基本操作。早い段階でしっかり慣れておくことが大切です。
インスタンス生成時に初期値を設定できる仕組み。現場でも必須の知識です。
データを安全に守る仕組み。アクセス修飾子(public・private)の使い分けを覚えましょう。
コードの再利用を実現する仕組み。基礎が固まっていれば自然と理解できます。
継承の次に学ぶことで、virtualとoverrideの使い分けが整理しやすくなります。
最後に学ぶことで、継承との違いや使い分けが整理しやすくなります。
最初から完璧に理解しなくても大丈夫です!まずはクラスを作って、インスタンスを作成して、メソッドを呼び出す流れに慣れることが大切です!
C#のオブジェクト指向でよくある質問


クラスとオブジェクトの違いは?



クラスとオブジェクトって、結局何が違うの?
詳しくは、この記事の「クラスとオブジェクトの違いとは」をご確認ください。
クラスはオブジェクトを作るための設計図、オブジェクトはクラスをもとに作られた実体です。
車で例えると「設計図 = クラス」「実際の車 = オブジェクト」のイメージです!
設計図だけでは走れないように、クラスを定義しただけではプログラムの中で扱うことができません。
newキーワードでインスタンス(オブジェクト)を作ることで、はじめてデータを持ち、メソッドを呼び出せるようになります。
インスタンスとオブジェクトの違いは?



インスタンスとオブジェクトって、どっちも同じじゃないの?
初心者のうちはほぼ同じ意味として理解して大丈夫です!厳密な使い分けは、基礎に慣れてから意識しましょう!
- インスタンス:クラスから作成されたことを強調した言葉
- オブジェクト:プログラムの中で扱うものとして見た言葉
参考書や記事によって使い方が異なることもあるので、どちらの言葉が出てきても「クラスから作った実体のことだな」と理解できれば問題ありません。
初心者はどこまで理解すればいい?



オブジェクト指向って覚えることが多すぎる



最初は何を理解すればいいんだろう?
まずは次の5つを理解できれば十分です。
- クラスは設計図
- インスタンスは実体
- プロパティはデータを持つもの
- メソッドは処理を行うもの
- インスタンス化は
newを使う
継承やポリモーフィズムは、基礎に慣れてから少しずつ学んでいきましょう。
まとめ


本記事では、C#のオブジェクト指向の全体像について解説しました。
重要なポイントをまとめると、次のとおりです。
- C#はオブジェクト指向をベースにしたプログラミング言語
- クラスは設計図、インスタンスは実体
- インスタンスとオブジェクトはほとんど同じ意味で使われる
- オブジェクト指向の4大原則は「抽象化・カプセル化・継承・ポリモーフィズム」
- 学ぶ順番はクラス → プロパティ → コンストラクター → カプセル化 → 継承 → ポリモーフィズム
オブジェクト指向は、最初から完璧に理解しようとすると難しく感じます。
まずはクラスを作成してインスタンスを生成し、メソッドを呼び出すという基本的な流れを体で覚えるところから始めてみましょう!

