C++/クラスの定義や継承

オブジェクト指向プログラミングとは、データや手続きを統一的に記述することで、プログラムの内容を理解しやすくするプログラミング手法です。
クラスはクラスベースのオブジェクト指向の中核となる概念で、 様々な言語でクラスを定義することが出来ます。 C++以外ではJava, Python, Ruby, Swift, Scala, Kotlin などがクラスベースのオブジェクト指向言語として有名です。
単純に、クラスベースのオブジェクト指向プログラミングに興味があるのなら、PythonやRubyなどの動的言語のクラスベースのオブジェクト指向プログラミングの方が、学習が容易と期待できるので、動的言語も検討するのも良いでしょう。
クラス(class)とは、データ構造であり、データと関数をメンバーとして持ち、実体(インスタンスと呼びます)を生成する時(インスタンス化)の雛型となります。
C++でクラスを宣言するには、キーワードclassを用いて次のように記述します。
class内の関数をメンバー関数(しばしばメソッド)、変数のことをデータメンバー(しばしばメンバー変数)と呼び、総称してメンバーと呼びます。 メンバーにはオブジェクトの外からアクセスできない非公開のもの private と、アクセスできる公開のもの public があります(継承の説明まで、protected の説明は留保)。 classのメンバーはデフォルトで非公開 private です。
メンバー関数がインライン化できない場合など、クラスの宣言の外にその定義を記述する事ができる。
その場合、メンバー関数の定義は、関数名の前に「クラス名::」を付けます。 「::(コロン2文字)」のことをスコープ解決演算子(scope resoluthion operator)と呼ぶ。 次のように記述する。
オブジェクトの生成(インスタンス化)は次のように記述する。
メンバーにアクセスするには、ドット(.)演算子を用いて次のように記述する。
カプセル化とは、オブジェクト指向のクラスにおいて、オブジェクトのデータ構造を直接操作するのではなく、クラスに用意してメソッド集合を使って操作する事です。
これは、クラスがオブジェクトの扱うためのすべてのメソッドを提供すべきだという考えに基づいており、関数や他のクラスのメソッドに頼るのは、クラス設計に問題があるという考え方です。
カプセル化の目的 ・オブジェクトへの統一的なインターフェースを提供し体系化できる。 ・内部構造を隠蔽することで、内部構造の変更が(継承したクラスを含む)クラスを利用するコードに波及しないようにできる。 ・設計手法的に観ると、分割統治法の一種として捉えられ、問題規模の縮小が図られる。
Javaなどの言語でも、カプセル化がサポートされています。 Pythonでは、カプセル化はデコレータなどで実現され、C++やJavaとは異なる方法でサポートされています。
C++では、public, private, protectedの3つのキーワードがアクセス制御として与えられています。 privateは、同じクラスに属するメソッドからしか値が呼び出すことができなくなります。 publicは、プログラムの他の部分からも呼び出せるようになります。 protectedは、クラスを継承した先から用いることが出来るようになります。 しかし、プログラムの他の部分から呼び出すことは出来ません。
ポリモーフィズム(polymorphism;多態性・多相性の訳語が充てられることが多い)は、同じ名前で複数の異なる振る舞いを作り、それを利用するオブジェクト指向の概念である。
ポリモーフィズムは、C++では関数のオーバーローディングによって実現される。 関数オーバーローディングとは、同じ名前の関数を複数実装・使用することである。 ただし、引数の型や個数が異ならないと関数オーバーロードできない。 また、戻値の型だけが異なる場合も関数オーバーロードできない。
C++のクラスには、初期化・終了処理を自動的に行うコンストラクタ・デストラクタ関数という仕組みがあります。
コンストラクタ関数(constructor function)あるいは単にコンストラクタは、オブジェクトが生成される際に呼び出され、主に初期化処理を記述する。
クラスにコンストラクタを追加するには、クラス宣言に以下のように記述します。
コンストラクタの名前は、そのクラス名と同じです。 コンストラクタは戻り値を返さないので、戻り値の型は指定しません。 コンストラクタには、引数を指定することができます。 コンストラクタも、関数オーバーロードできます。 引数のないコンストラクタを、ディフォルトコンストラクタと呼びます。

デストラクタ関数(destructor function)あるいは単にデストラクタは、オブジェクトがスコープを似ける時、あるいは delete 演算子で解放される際に暗黙に呼び出され、主に終了処理を記述します。
クラスにデストラクタ関数を追加するには、クラス宣言に以下のように記述します。
デストラクタの名前は、そのクラス名の前に~チルダーを付けます。 デストラクタは戻り値を返さないので、戻り値の型は指定しません。 デストラクタには、引数を指定することができません。 デストラクタは、関数オーバーロードできません。 引数も戻り値の型も指定しない。
フレンド関数(friend function)は、メンバー関数ではない普通の関数から、クラスのprivateまたはprotectedメンバーにアクセスしたい場合に使います。
この特徴だけ書くと、フレンド関数はカプセル化を破壊するように思えますが(事実その様な設計の失敗は観られますが)、メンバー関数では出来ない呼出し形式がふさわしい場合に利用価値があります。
具体的には、演算子オーバーライドがメンバー関数では出来ない呼出し形式の1つです。 ユーザー定義クラスを、ストリームに << で出力する場合
C++11からは、キーワード friend を使った構文が拡張され、 class を指定できるようになりました。 friend 宣言された class のメソッドとstaticメンバー関数は、friend 宣言した class のメンバーに、フリーハンドにアクセスできます。
C言語では、標準ライブラリ関数の malloc() と free() などを使って動的にメモリーを確保しました。
C++では、同様の機能を new 演算子と delete 演算子 を使って実現します。
初期化と代入は、どちらも等号を使って表現できるので混同しがちですが、両者は明確に異なるものです。
もしクラスで、ディフォルトコンストラクター・コピーコンストラクター・コピー代入演算子を定義しなかった場合は、C++コンパイラは、
と自動的にコードを生成します。この動作は、メンバーがすべて静的な場合には好ましいものです。
逆に言うと、いずれかのメンバーが動的な場合、具体的には new 演算子で確保された領域へのポインター(やリファレンス)が含まれていた場合、ポインター(あるいはリファレンス)の単純な複製が初期化先あるいは代入先に複製されると、2つのインスタンスが同じ領域を(不本意に)共有してしまうので好ましくありません。 この様な場合は、コンパイラのお仕着せではなく、カスタムメイドのコピーコンストラクターとコピー代入演算子を用意する事になります。

継承とは、オブジェクト指向の考え方の一つで、 あるクラスの性質を受け継いだ別のクラスを定義することである。 継承によって、汎用的なクラスから特化したクラスを作ることができる。
あるクラスを別のクラスが継承するとき、 継承されるクラスを基本クラス(base class)と呼び、 継承するクラスを派生クラス(derived class)と呼ぶ。
基本クラスでは、共通の性質を定義し、 派生クラスでは、その共通の性質を受け継いだうえで、 個別の性質を定義する。 クラスの継承の仕方は次のとおりである。
派生クラス名で派生クラスの名前をしてする。 アクセス指定子ではpublic, private, protectedのいずれかを指定する。 基本クラス名で基本クラスの名前を指定する。
クラスと構造体の違いは、クラスはデフォルトでメンバーがprivateであるのに対し、構造体はデフォルトでメンバーがpublibであるだけです。
一方、共用体にはいくつかの制限があります。
テンプレート:Nev