【C++】オブジェクト指向プログラミングが超重要な理由
Published: 2023-06-07 14:34:46

オブジェクト指向プログラミング(Object Oriented Programming)を学んでみたものの、「...だから何？」と感じている方もいるかもしれません

本記事を読めば、普段のプログラムの構造(手続型)とOOPの2つの大きな違いと、それぞれのメリット・デメリットが理解できます

それと共に、OOPが何故めちゃくちゃ重要且つパワフルなのかを解説していきます

---


## 手続型プログラミングとOOP


手続型とOOの2つのプログラムの構造に分けられる意義は「プログラムの規模」にあります

---

### 手続型プログラミング


これは「特定の処理を目的とした関数を複数作ることで、プログラムをモジュール化」という考え方に基づいています

**要は、単に1つ以上の関数を羅列しただけのプログラムです**  
 
#### データと関数はそれぞれ独立して作成される

関数のスコープ外のデータにアクセスするには関数実行時に引数としてデータを置く必要があります

 
例えば、名前・学籍番号・専攻の3つの情報をもつ学生のデータを表現してみましょう
それに加えて、学生は設定情報を更新する機能をもつとします


``` cpp
#include <string>
#include<iostream>

using namespace std;

void intro(string name, string faculty)
{
    cout<< name << " majors " << faculty<<endl;
}

int main() {
    string name = "Rei";
    int number = 31500;
    string faculty = "CS";
    //関数introで上記のデータを使用するには引数として渡す必要がある
    intro(name, faculty);
    
    return 0;
}
```


手続き型では名前、学籍番号、専攻の各項目の具体的な情報を持ったデータと、それらのデータの編集機能をもつ関数を宣言していることがコードから分かると思います

####手続型のメリット：

  - 直感的にプログラムが書ける(**プログラミングにおいて凄く重要**)

→規模が小さいプログラムの構築に最適

####手続型のデメリット：

  - プログラムの規模がある程度大きくなると、エラーが起きやすくなる上にデバッグが大変

  - 関数が扱うデータの構造が変われば、関数内の処理も変わることがある

  - 手続型プログラミングの構造上、データと関数は切り離されているので、関数内で処理されるデータが引数であった場合、その引数であるデータに変更が生じた場合は関数内の挙動も変わる可能性がある

  →例えばデータを引数として複数の関数に渡していた場合などは、それら全ての関数内でデバッグ等を行うことに

  - 関数が多すぎて可読性が落ちる

  - 結局各関数がどのような機能を持っているのかが分からなくなる

  - 別のプログラムで特に引数を持っている関数を再利用するのが難しくなる

---

###オブジェクト指向(OO)

**OOの本質は「抽象化」です**

少し難しく言うと、ソフトウェアをクラスとオブジェクトを用いてモデル化することがオブジェクト指向の目的と言えます

上の学生データを例にしてみましょう


OOでは、「**全ての学生は共通して名前、学籍番号、専攻の情報と編集機能をもつのだから、データと関数を1つの塊にまとめてしまえば良い**」と考えます


この時の「塊」がオブジェクトであり、データとそのデータに関係する関数をまとめた1つの塊として考えることをカプセル化(Encapsulation)と呼びます


そして、オブジェクトはクラスを用いていくつも作成出来ます

つまり、クラスはオブジェクトの設計図であり、オブジェクトの持つデータ項目・関数を定義します

また、クラスで作成されたデータは属性(Attribute)とよび、関数はメソッドと呼ぶことは覚えておきましょう

それでは、ここで実際に学生データをいくつか作成してみましょう。


まずは手続型で実装してみると

``` cpp
#include <string>
#include<iostream>

using namespace std;

void intro(string name, string faculty)
{
    cout<< name << " majors " << faculty<<endl;
}

int main() {
    string name_rei = "Rei";
    int number_rei = 31500;
    string faculty_rei = "CS";
    string name_kiku = "Kiku";
    int number_kiku = 67721;
    string faculty_kiku = "Management";
    string name_ryu = "Ryu";
    int number_ryu = 77321;
    string faculty_ryu = "Literature";

    intro(name_rei, faculty_rei);
    intro(name_kiku, faculty_kiku);
    intro(name_ryu, faculty_ryu);
    
    return 0;
}
```


学生データを複数個作成する場合、学生の数だけ繰り返し各項目のデータを宣言する必要があり、これだけでも冗長になってしまっていることが分かります。


一方のOOPの同じ処理の実装を見てみましょう

```cpp
#include <string>
#include<iostream>

using namespace std;

class Student{
public:
    // Attributes
    string name;
    int number;
    string faculty;

    // Methods name,facultyは両方このクラス内の属性なのでメソッドに引数は不要
    void intro()
    {
        cout<< name << " majors " << faculty<<endl;
    }
};

int main() {
//作成されたオブジェクトデータはインスタンスと呼ばれます
    Student student1;
    student1.name = "Rei";
    student1.number = 31500;
    student1.faculty = "CS";

    Student student2;
    student2.name = "Kiku";
    student2.number = 67721;
    student2.faculty = "Management";

    Student student3;
    student3.name = "Ryu";
    student3.number = 77321;
    student3.faculty = "Literature";
    
//メソッドの実行
    student1.intro();
    student2.intro();
    student3.intro();

    return 0;
}

```

上記を見ると、例えば手続型で作成されたname_reiなどの、学生の持つ各項目となる特定のプロパティの作成が不要になっています。

また、今回はコンストラクタは使用していませんが、コンストラクタを用いると、各インスタンスの属性を毎回プロパティ名を指定して設定する必要がなくなり超スッキリします。

**コンストラクタはOOPで最もパワフルなメソッドの1つ**ですので、OOPの学習では必ず押さえておきたい概念です。

[コンストラクタとディコンストラクタ、コピーコンストラクター・ムーブコンストラクターを使いこなす](https://google.com)


####OOPのメリット：

  
- データ項目や機能をクラス内で定義したら、それらの変数・メソッドを持ったオブジェクトを無数に作ることが可能→再利用性(Reusability)


- 互いに関係性のあるデータと関数を1つのクラスにまとめるので、可読性(Readbility)が高い


- 特定のオブジェクトにおけるエラーが起きた時などは、大抵クラス内での実装に問題があるので、デバッグが容易


- **Information-hiding**

1. クラス内で実装された属性・メソッドはクラス内でのみアクセスが可能。これによってクラス外からクラスの属性に誤って意図しない変更を加えてしまったりする心配がなくなる
2. クラス内の属性・メソッドのアクセスの権限にはprivate(これはデフォルト), public, protectedの3タイプある

    →[private/public/protectedとstructとclassの比較](https://google.com)


- 作成したクラスを別のクラスの実装時に再利用できる


→クラスには継承(Inheritance)という概念があり、あるクラスで別のクラスのメンバ変数・メソッドにアクセスが出来るようにすることが出来る

  →[オブジェクト指向プログラミングの継承](https://google.com)


####OOPのデメリット：

  - 手続型に比べて実装が面倒→規模が小さかったり、機能面でシンプルなアプリなどをわざわざOOPで実装したらムダに実装が複雑になる

  - 特にC++はクラスにおいて様々な機能を持ち合わせていることもあり、クラス内の処理が複雑になりがち

---

以上より、2つのプログラム構造はそれぞれメリット・デメリットを持っているので、目的に応じて使い分けるのがクレバーだということが分かりますね