今まで構造化プログラミングばかりやっていてろくにオブジェクト指向を知らないmimizuがC++で初めてオブジェクト指向を使うための備忘録的記事です。
オブジェクト指向とは
オブジェクト指向とは、データやその操作方法(つまり変数や関数)をひとまとめにして、もの(オブジェクト)として扱うプログラミングの方法です。
これはどのように実現するかというと、まずクラスというものを作ります。
これには変数の宣言や関数の定義が記述されており、モノの設計図となるものです。
そして、次にこのクラスを型とする変数を宣言します。
これはインスタンスと呼ばれるもので、実体のあるモノになります。
インスタンスはクラスに記述された設計図から作ったモノであり、クラスの定義に記述された変数や関数を自身の中で使うことができます。
ちなみに、C++の場合はクラスに属する関数をメンバ関数と呼びます。
これは他のオブジェクト指向の言語ではメソッドと呼ばれるものです。
クラスのいろいろ
クラスの定義の仕方
#include <iostream>
using namespace std;
class クラス名{
ここでメンバ変数・関数の宣言・定義
};
int main(){
クラス名 インスタンスとなる変数名;
}
C++でオブジェクト指向プログラミングをするにあたって、まず次の書き方・使い方を学びます。
- アクセス指定子(public, private, protected)の使い方
- コンストラクタとデストラクタの使い方
- 静的メンバ変数・関数の使い方
- 継承の仕方と継承修飾子
アクセス指定子
アクセス指定子にはpublic, private, protectedの3つがあります。
これは主にクラスの外部から変数や関数に対してアクセスできるかどうかを決めるためのものです。
(protectedはまず「継承」を知る必要があるので後述します。)
アクセス指定子は次のように使います。
#include <iostream>
using namespace std;
class クラス名{
private:
ここでメンバ変数・関数の宣言・定義
public:
ここでメンバ変数・関数の宣言・定義
};
このようにして、メンバ変数や関数にアクセスの指定をします。
privateに含まれる関数や変数は、クラスの中・メンバ関数の中からしか使うことができなくなります。
これはカプセル化といい、クラスの独立性を高めます。
外からデータが誤って変に書き換えられることを防ぐ他、独立性を高めたり、無駄をなくして部品としての使い勝手を良くします。
publicに含まれる関数や変数は、クラスの外から使うことができます。
main関数の中でインスタンスに対して使いたいメンバ関数や、アクセスしたい変数はこちらに含めます。
コンストラクタとデストラクタ
コンストラクタは、インスタンスが作られた際に自動的に実行されるメンバ関数です。
主に初期化処理に使います。
デストラクタは、インスタンスがメモリから破棄される際に呼び出されます。
これらは返り値を持ちませんが、voidとは書きません。
#include <iostream>
using namespace std;
class Node{
public:
Node(); //コンストラクタの宣言(クラス名と同じ名前にする)
~Node(); //デストラクタの宣言(クラス名に~をつけたものにする)
};
このように、コンストラクタはクラス名と全く同じ名前の関数とすることで宣言できます。デストラクタはこれに~をつけたものとして宣言できます。
また、voidは付けず、アクセス指定子はpublicとします。
静的メンバ変数・関数
静的メンバ変数・関数は、すべてのインスタンスに共通するメンバ変数・関数です。
そのため、すべてのインスタンスで同じ値を参照したいとか、同じものになるから一つだけでいいというときに使います。
グローバル変数・関数のようなものです。
静的メンバ変数・関数は普通の宣言の前にstaticとつけることで宣言でき、静的メンバ変数の値は自動で0に初期化されます。任意の値に初期化することもできます。また、インスタンスを作る前でも実体をもち、インスタンスを作る前から使うことができます。
継承
継承は、すでに定義してあるクラスを引き継いで新しいクラスを定義することです。
基になるクラスをクラスを基底クラス(または基本クラス)といい、それを基に新しく作ったクラスを派生クラスといいます。
継承をするには、次のように書きます。
#include <iostream>
using namespace std;
class 派生クラス名 : 継承修飾子 基底クラス名{
ここに派生クラス独自の内容
};
例えば
#include <iostream>
using namespace std;
class Animal{
クラスAnimalの内容
};
class Cat : public Animal{
クラスAnimalから派生したCatクラス
};
という感じです。
基のクラスを直接書き換えて壊してしまうリスクを取らずに機能を変更・追加したクラスを作ることができるということが継承の主なメリットの一つです。
アクセス修飾子と継承修飾子
先ほど3つのアクセス修飾子のうち、publicとprivateの2つを説明しました。
復習しておくと、アクセス修飾子とは変数や関数が外部からアクセス(変数の値の参照・変更や関数の呼び出し)が可能かなどを決めるもので、publicはそのクラスの外部からもアクセス可能、privateはクラスの内部でのみアクセス可能とするものでした。
そして3つのうち説明していなかったアクセス修飾子がprotectedでした。protectedは、そのクラス内ではprivateと同様に外部からアクセスできないようになりますが、派生クラスからはアクセス可能とするものです。
一方でprivateは派生クラスからはアクセスできません。
ですので継承されそうなクラスではprivateとしたいところはprotectedにしておくのが無難です。
また、これら3つのもう一つの使い方が継承修飾子です。
継承修飾子は、クラスを継承するときに基底クラスの変数と関数のアクセス修飾子をどのように引き継ぐのかを決定します。
先の例での派生クラスAnimalの手前に書いたpublicはこの継承修飾子です。
継承修飾子の役割は
- public:基底クラスのアクセス修飾子をそのままに引き継ぐ
- private:基底クラスのメンバ変数・関数をすべてprivateにして引き継ぐ
- protected:基底クラスのpublicを全てprotectedにして引き継ぐ
となっています。
この継承修飾子があるおかげで、継承するときになって基底クラスのアクセス修飾子を直接変更しようとしなくて済みやすくなります。
実際にはそのまま引き継ぐpublicが最も多く使われ、次にprotectedがよく使われるようです。
C++のクラスを用いたオブジェクト指向プログラミングを試すために、
配列とポインタの2通りで二分探索木を実装してみました。
オブジェクト指向や二分探索木に興味があればぜひ見てみてください。