C++/C++特有の概念

< C++

C++とは編集

 
ビャーネ・ストロヴストルップ

C++は、1979年、 米国ニュージャージー州マレーヒルのベル研究所で、 ビャーネ・ストロヴストルップによって開発された、 オブジェクト指向型のプログラミング言語である。 何度かの改訂、 アレクサンダー・ステパノフによる標準テンプレートライブラリ(STL)の作成を経て、 標準化されている[1]

C++は、Cを拡張してより使いやすい言語にすることを目指して作成された。 実際には、現在でもCは非常に人気のある言語であり続けている。 このことには、様々な理由が考えられるが、 例としては、

  1. Cはよく用いられる言語なので、他人のコードを読むためには、Cを勉強する必要がある。
  2. C++は、Cよりも機能が多く、勉強するのに時間がかかる。
  3. C++が提供する機能は、ある程度大きいコード以外ではあまり用いる機会がない。

等があげられる。

C++が提供するCの拡張として以下の機能があげられる。 これらは、Cを用いる上でたびたび現れる問題に対応するために導入された。

  1. クラスの定義や継承
  2. 関数や演算子のオーバーロード
  3. テンプレート
  4. 仮想関数
  5. 例外処理
  6. 名前空間

[2]

CとC++の相違点編集

要点編集

  1. Cでは引数がない関数の関数原型の引数のリストにはvoidを指定する。一方、C++ではvoidの指定を省略できる。
  2. Cでは関数原型の記述は推奨されるが任意である。一方、C++では必ず記述しなければならない。
  3. Cでは関数の戻り値の型がvoid以外の時でもreturn文で値を指定しなくともよい。一方、C++では必ず指定しなければならない[3]
  4. Cでは関数の戻り値の型を省略すると整数型が使われる。一方、C++では必ず型を指定しなければならない。
  5. Cではかつてローカル変数の宣言はブロックの先頭で行う必要があった(この制限は、C99 で撤廃された)。一方、C++ではどこで行ってもよい。
  6. Cではbool型が標準設定には無い(C99で_Bool型が予約語に追加されたが、ライブラリ stdbool.h を導入する必要がある)。一方、C++では初期設定のままbool型を使える。

Cの基礎知識については、『C言語/基礎知識』を参照してください。 ただしprintf関数とscanf関数については、後述する#コンソール入出力で、より改善されたとC++開発者が考える方法を用いるため、学習する必要はあまりありません。

Hello, World!を実行する編集

はじめてソースコードを書くときは、 まず「hello, world」プログラムと呼ばれる 画面に「hello, world(改行)」とだけ表示するプログラムを、 書くことにしましょう。

C++はCを拡張して作られているため、 Cと似た部分が多くあります。 例えば、次のCで書かれたプログラムはC++でも正しいプログラムです。 このプログラムの解説はC言語/はじめに#Hello, World!を実行するを参照してください。

#include <stdio.h>

int main(void)
{
	printf("hello, world\n");
	return 0;
}

しかし、C++では、一部機能が追加されて、また入出力はより直観的な方法を使うことができるようになりました。 以下は同じ内容をC++の機能を用いて書き直したものです。

#include <iostream>
using namespace std;

int main() 
{
    cout << "hello, world" << endl;
    return 0;
}

ここではこのソースコードについて簡単に説明します。

  • 1行目は、新しいスタイルのヘッダです。
    Cでは#include <stdio.h>のようにファイル名を指定しましたが、これは古いスタイルのヘッダで、C++では新しいスタイルのヘッダを使い、標準識別子を指定します。新しいスタイルのヘッダは、ファイル名ではないので「.h」拡張子がありません。古いスタイルのヘッダは、引き続き使用できますが、推奨されません。標準Cヘッダを新しいスタイルで書くと、頭にcが付きます。例えば、#include <stdio.h>#include <cstdio>となります。
  • 2行目は、std名前空間で定義された識別子(この場合は cout)を std:: 前置句なしに参照可能にしています。
  • 3行目は、任意の空白行です。
  • 4行目から8行目は、main関数の定義です。
  • 5行目から8行目は、ブロックというまとまりです。
  • 6行目は、出力演算子による出力操作です。
    Cではコンソール出力に、printf関数を用いましたが、C++では「<<演算子」を使って、改善された方法で出力を行うことができます。Cでは<<は左シフト演算子でしたが、C++ではその機能に加えて、出力演算子として用いることができます。これは後で解説する演算子のオーバーロードの例でもあります。
  • 7行目は、return文です。
  • 6と7行目が、空白によって右側に偏っているのは、インデントのためです。

オブジェクト指向との関連編集

クラスを用いたプログラムをオブジェクト指向プログラムと呼びます。 そのため、上のC++のhello, worldの例はオブジェクト指向プログラムの例です。 この例で用いられているオブジェクト指向について簡単にまとめます。

この例では、オブジェクト指向を導入した結果として、

"hello, world"という文字列をprintfする

という考えから、

coutと呼ばれるデータに"hello, world"という文字列を与えて、cout自身にそれを解釈させる

という考えへの移行が行われています。

ここで、coutのようにある演算に対してどう振る舞えばよいか知っているデータのことを、オブジェクトと呼びます。 上の例では、coutと呼ばれるオブジェクトに対して、定義された演算<<を用いました。 この例は短いのでわかり辛いのですが、 cout自身が文字列の扱い方を知っていることはプログラムを簡単にします。

例えば、Cでは標準出力に出力する時には次のようにprintf関数を使いました。

printf("abc");

一方、ファイルに出力する時には次のようにfprintfという異なる関数を使う必要があります。

fprintf(f, "abc");  // fはファイルポインタ

これは、扱う対象が異なっている以上当然ですが、 出力する対象の数が増えて来るとわかりづらくなります。

一方、C++を用いると、標準出力に対しては、

std::cout.operator<<("abc");

ファイルに対しても、

f.operator<<("abc"); // fはファイルストリーム

となり、同じ名前の関数 operator<< を用いることが出来ます。

ここで、 operator<< は、それが所属するオブジェクト(実際にはオブジェクトが所属するクラス)によって動作が変化していることに注意が必要です。 このように、データ自身が実際の動作を知っていることで、 様々なデータを統一的に扱うことが出来ます。

もちろん、オブジェクト自身を設計する時には、 データを統一的に扱えるようにクラスを設計する必要があるため、 Cの例の場合より必ずしも仕事が簡単になる訳ではありません。 しかし、これらを使う側に取っては、C++の例の場合の方が分かりやすいといえるでしょう。

  • 注意

実際に<<演算子を用いた演算を行う時には、

cout << "abc";

の部分は、

cout.operator<<("abc");

というメソッドの呼び出しに書き換えられて実行されます。

上の説明ではこのことを前提としています。

オブジェクト指向編集

オブジェクト指向プログラミング(Object-Oriented Programming : OOP)は、 コンピュータプログラムの構造、構成法の一つで、 関連するデータの集合体と、 それを操作する手続きを「オブジェクト」(object)と呼ばれるひとまとまりの単位として一体化し、 オブジェクトの組み合わせとしてプログラムを記述する手法である。 [4]

プログラミングでは、どんどん複雑になっていくプログラムに対応するために、新しい手法が次々と作られてきた。

最初は、フロントパネルのスイッチをオンオフすることによって、ごく短いプログラムが作成された。

次に、アセンブリ言語によって、より長いプログラムが作成できるようになった。

そして、1950年代、最初の高レベル言語(FORTRAN)が開発されたことによって、数千行にわたるプログラムが作成できるようになった。 しかし、何でも許される方式であったため、大きなプログラムを書こうとすると、読みづらく保守しにくい「スパゲティコード」となってしまった。

1960年代には、構造化プログラミング言語(structured programming language)の登場で、スパゲティコードを排除し、五万行に及ぶプログラムを作成し、保守できるようになった。

Cも広い意味では構造化プログラミング言語である。構造化プログラミング言語では、制御構造を使い、プログラムを構成要素に分割して記述する。

しかし、構造化プログラミング言語も、プログラムの長さが一定に達すると限界に達するだろうと危惧されるようになった(しかし現実は2020年でも、たとえばLinuxのカーネルは標準C言語で記述されているが)。

オブジェクト指向プログラミングでは、前述したとおり、プログラムを自己完結したオブジェクトとして記述することで、複雑さを軽減し、より巨大なプログラムを記述できるようにした。

C++におけるオブジェクト指向プログラミングには、カプセル化、ポリモーフィズム、継承の3つの特色がある。 これらについて説明していく。

カプセル化編集

カプセル化(encapsulation)とは、 データとそれを操作する手続きを一体化して「オブジェクト」として定義し、 オブジェクト内の細かい仕様や構造を外部から隠蔽することである。 [5]

手続きとデータを一体化し、手続きによってしかデータを操作できないようにすることで、ブラックボックスなオブジェクトを作成し、独立性を高めている。

さらにC++におけるカプセル化では、データと手続きを、非公開(private)と公開(public)に分けて、 オブジェクトの外部からは、非公開のものにはアクセスできず、公開のもののみにアクセスできるようにしている。

カプセル化によって、保守性や開発効率を挙げることができ、コードの再利用も簡単になる。

ポリモーフィズム編集

ポリモーフィズム(polymorphism、多相性、多態性、多様性)とは、 同名のメソッドや型などをオブジェクトの種類に応じて使い分けることができる性質のことである。 [6]

ポリモーフィズムでは、 同一の名前で複数の異なる動作を作成し使うことができる。

例えば、Cで絶対値を求めるには、 引数のデータ型に合わせて、 abs(), labs(), fabs()の3つの関数を使い分ける必要がある。 一方、C++で絶対値を求めるには、 引数がどのデータ型であっても、 abs()という1つの関数で求めることができる。

このように1つの関数名を複数の異なる目的で使うことを、 関数のオーバーロード(function overloading)という。

ポリモーフィズムの利点は、 メソッド名を統一することで、 記述ミスを減らせるなどが挙げられる。

継承編集

継承(inheritance)とは、 既に定義されているクラスをもとに、拡張や変更を加えた新しいクラスを定義することである。 [7]

継承を使うことで、 あるものの性質を受け継ぎ独自の機能を追加することができる。

例えば、哺乳類を継承し人、犬、猫を新たに作るといった考え方ができる。

関数などによってもコードの再利用は可能だが、さらに継承によって、より自由にコードの再利用ができるようになる。

脚注編集

  1. ^ 神林靖監修 Herbert Schildt著『独習C++ 第3版』トップスタジオ訳、翔泳社、2005年11月05日 第3版第10刷発行、p. iii
  2. ^ C++言語とは - 意味/定義 : IT用語辞典
  3. ^ main()の戻り値がintであった場合に限り省略可能で return 0; が仮定される。
  4. ^ オブジェクト指向プログラミングとは|OOP|Object Oriented Programming - 意味/定義 : IT用語辞典
  5. ^ カプセル化とは|encapsulation - 意味/定義 : IT用語辞典
  6. ^ ポリモーフィズムとは|polymorphism|ポリモルフィズム|多相性 - 意味/定義 : IT用語辞典
  7. ^ 継承とは|inheritance|インヘリタンス - 意味/定義 : IT用語辞典

参考文献編集

  • 神林靖 監修 Herbert Schildt著『独習C++ 第3版』トップスタジオ訳、翔泳社、2005年11月05日 第3版第10刷発行