C++

提供: miniwiki
移動先:案内検索
C++
拡張子 .cc, .cpp, cxx; .h, .hpp
パラダイム マルチパラダイム手続き型プログラミングデータ抽象オブジェクト指向プログラミングジェネリックプログラミングの組み合わせ)
登場時期 1983年
設計者 ビャーネ・ストロヴストルップ
最新リリース ISO/IEC 14882:2017/ 2017年12月1日(6年前) (2017-12-01
評価版リリース ISO/IEC 14882:2017
型付け nominative, 安全でない強い静的型付け
主な処理系 GCC
Clang
Microsoft Visual C++
Intel C++ Compiler
C++ Builder
影響を受けた言語 C言語SimulaAda
影響を与えた言語 JavaC#D言語PHP
ウェブサイト isocpp.org
テンプレートを表示

C++シープラスプラス)は、汎用プログラミング言語の一つである。日本語では略してシープラプラシープラなどとも呼ばれる。

概要

1983年にベル研究所のコンピュータ科学者のビャーネ・ストロヴストルップが、C言語の拡張として開発した。当時の名前は「C with Classes」(クラス付きのC言語)だった。拡張はクラスの追加に始まり、仮想関数多重定義多重継承テンプレート例外処理といった機能が続いていった。

標準規格化がISOIEC共同で行われており、現在最新のバージョンは、2017年に制定されたISO/IEC 14882:2017、通称「C++17」である。

表現力と効率性の向上のために、手続き型プログラミングデータ抽象オブジェクト指向プログラミングジェネリックプログラミングの複数のプログラミングパラダイムを組み合わせている[1]アセンブリ言語以外の低水準言語を必要としない、使わない機能に時間的・空間的費用を要しないことが、言語設計の重要な原則となっている[2][3]。また、静的な型システムを持つ。

歴史

ストロヴストルップはプログラミング言語C with Classesの開発を1979年に開始した。彼は大規模なソフトウェアの開発に有用な特徴をSimulaが備えていることに気がついたが、Simulaは実行速度が遅く実用的ではなかった。一方でBCPLは実行速度こそ速かったものの、大規模なソフトウェア開発を念頭に置いた場合にあまりにも低級だった。

これらの事情を鑑みて、ストロヴストルップは当時既に汎用的な言語だったC言語にSimulaの特徴を取り入れることを試みた。この取り組みにあたってはALGOL68AdaCLUML等の言語の影響も受けている。最初はクラスと派生クラス、型検査機構の強化、インライン関数、デフォルト引数の機能を、Cfrontを介してC言語に追加した。1985年10月に最初の商用リリースがなされた[4]

1983年にはC with ClassesからC++に名称を変更した。この際に、仮想関数と、関数と演算子の多重定義参照型、const型、ユーザー制御可能な自由領域メモリ制御、型検査機構の改良、BCPL形式(「//」による)の行単位のコメントアウトなどの機能が追加された。1985年には『The C++ Programming Language』の初版が出版された(邦訳『プログラミング言語C++』1988年))。この時点では公式な標準が策定されていなかったために、この本が事実上のリファレンスとなった。1989年C++のヴァージョン2.0として、多重継承抽象クラス、静的メンバ関数constメンバ関数、protectedメンバ等の機能が追加されたものがリリースされた。1990年に『The Annotated C++ Reference Manual (ARM)』[5](邦訳『注解C++リファレンスマニュアル』[6])が出版され、将来の標準化の土台となるものを提供した。後に追加された機能にはテンプレート例外処理名前空間、新形式のキャストブール型が含まれた。

ARMが事実上の標準として使われた時代が続いたが、標準化が進んだ。C++言語の最初の標準は1998年にISO/IEC 14882:1998として承認された。2003年の改訂版を経て、2011年にメジャーアップデートとして制定されたのがISO/IEC 14882:2011、通称「C++11」である。このバージョンは、元々、非公式に「C++0x」と呼ばれていた。2000年代中に制定され、正式に「C++09」と呼称されることを見越した仮称だったが、2000年代中には実現しなかった。2011年8月10日まで続いた最終国際投票で C++0x は全会一致で承認された。これにより C++0x と呼ばれてきた C++ の次期改正案はついに国際標準になり、C++11と呼べるようになった。また、2014年にはISO/IEC 14882:2014、通称「C++14」が策定された。2018年現在の最新バージョンは2017年に策定されたISO/IEC 14882:2017、通称「C++17」である。2020年にはISO/IEC 14882:2020、「C++20」が策定される予定である。

C++言語の進化に伴い、標準ライブラリもまた進化していった。C++標準ライブラリに最初に追加されたのは、従来のC言語の printf()scanf() といった関数を置き換えるストリームI/Oライブラリである。また、C++98における標準ライブラリへの追加で最も重要なものはStandard Template Library (STL)である。C++11では、正規表現による検索・置換や複数スレッドでの同時実行、ハッシュテーブル・ハッシュセットの追加などさらなる拡充が続いている。

標準規格

規格制定日 C++ 標準規格 非公式名称
1998年9月1日 ISO/IEC 14882:1998[7] C++98
2003年10月16日 ISO/IEC 14882:2003[8] C++03
2007年11月15日 ISO/IEC TR 19768:2007[9] C++TR1
2011年9月1日 ISO/IEC 14882:2011[10] C++11
2014年12月15日 ISO/IEC 14882:2014[11] C++14
2017年12月 ISO/IEC 14882:2017[12] C++17
2020年予定 C++20

長年にわたる作業の後、ANSIとISOの合同委員会はC++言語を1998年に標準化した(ISO/IEC 14882:1998)。1998年の標準の公式なリリースから数年間に渡って委員会は不具合の報告を続け、2003年に訂正版を出版した。2003年12月に制定された日本工業規格JIS X 3014:2003(プログラム言語 C++)は、ISO/IEC 14882:2003(E)の日本語への翻訳である。

2007年11月15日に『C++ Technical Report 1』 (TR1)というテクニカルレポートがリリースされた。これは標準の公式な一部ではないが、次のバージョンのC++に含まれると期待される、標準ライブラリへの数多くの拡張を与えた。TR1の内容は、多少の修正を加えてC++11に取り込まれている。

2011年9月1日、C++98以来初の大きな改訂となるISO/IEC 14882:2011が発行された。

2014年8月18日、ISO/IEC 14882:2014(C++14)が投票で承認され[13]、2014年12月15日、公式に出版された。

2017年12月、ISO/IEC 14882:2017(C++17)が公式に発行された。

現在、C++20の仕様策定が進められている。

将来

C++に対しては、今もなお要望が絶えない。特にBoostはC++の方向性の決定に大きく貢献し、さらにC++標準化委員会へ改良すべき点などを意見している。現在はマルチパラダイムプログラミングをより自然に行えるようにすることに力が注がれており、たとえばBoostでは、C++の関数型プログラミングメタプログラミングの可能性を模索している。

C++11と呼ばれている新しいバージョンのC++標準ではこれらの一部が取り込まれ、今後のC++でもさらなる追加が行われると見られている。

C++という名称

この名称はRick Mascittiの功績で、最初に使用されたのは1983年の12月である。初期の研究期間では、開発中の言語は「C with Classes」と呼ばれていた。最終名は、変数の値を一つ加算する、C言語の++インクリメント)演算子からの派生である。また一般的な命名規則での「+」の使用は、機能強化されたコンピュータプログラムを意味する。ストロヴストルップによれば「この名前は、C言語からの変更の革新的な本質を示している」ということである。C+は、より初期の無関係なプログラミング言語の名前である。

ストロヴストルップは著書『The C++ Programming Language』の前文で名前の起源を語り、ジョージ・オーウェルの小説『1984年』の付録から「C++」が連想されるかもしれないと付け加えている。新語法という架空の言語の解説に宛てられた3つの章の中に、科学技術に関する専門用語とジャーゴンの解説に宛てられた「C vocabulary」という章がある。新語法で「ダブルプラス」は最上級の修飾語である。ゆえに新語法で「C++」は「最も極端な専門用語またはジャーゴン」という意味になるだろう。

1992年、Rick Mascittiは名前について非公式に質問されると、彼はおふざけのつもりで命名したという旨の回答をした。彼はこの言語の正式な名称になるとは夢にも思っていなかった。

哲学

ビャーネ・ストロヴストルップは著書『C++の設計と進化(1994)』でC++を設計する際に用いたルールを述べている。

  • C++はCと同等の実行効率と移植性を持つ静的に型付けされた汎用言語である。
  • C++は直接的かつ包括的に複数のプログラミングスタイル(手続き型プログラミング抽象化オブジェクト指向ジェネリックプログラミング)をサポートする。
  • C++はもしプログラマが間違っている可能性があったとしてもプログラマに選択の余地を与える。
  • C++は可能な限りC言語との互換性を持ち、C言語からスムーズに移行できる。
  • C++はプラットフォームに固有な機能や汎用的でない機能の実装を避ける。
  • C++は利用しない機能についてはオーバーヘッドが生じない(ゼロオーバーヘッドの原則)。
  • C++は高級な実行環境を必要としない。

C++のコンパイラがどのようにコードを出力しメモリのレイアウトを決めるのかということについては『Inside the C++ Object Model』(Lippman, 1996)に記載されている。ただしコンパイラが出力するコードの仕様はコンパイラ制作者の裁量に任されている。

標準ライブラリ

1998年に施行されたANSI/ISO C++ 規格は言語仕様とライブラリの2つのパートで構成される。ライブラリ規格の大半はStandard Template Library (STL)とC言語の標準ライブラリの改良版についての内容である。標準規格以外にも様々なライブラリが数多く存在し、リンカを使用することにより、C言語FORTRANPascalBASICのような言語を用いて作成されたライブラリを利用できる。規格外のライブラリが利用できるかどうかはコンパイラに依存する。

C++標準ライブラリはC++向けに若干の最適化が施されたC言語標準ライブラリを含んでいる。C++標準ライブラリの大部分はSTLである。 コンテナ可変長配列リストなど)、コンテナを配列のように扱えるようにするイテレータ、検索やソートを行うアルゴリズムといった有用なツールが提供されている。さらにmapmultimapのような連想配列や、setmultisetのようなソート済みコンテナも提供され、これらは全てインターフェイスに互換性がある。テンプレートを用いることにより、あらゆるコンテナ(またはイテレータで定義したシーケンス)に適用できる汎用的なアルゴリズムを記述できる。C言語と同様にライブラリの機能には#include ディレクティブを使ってヘッダファイルを読み込むことによってアクセスする。C++には69本の標準ヘッダファイルがあるが、このうち19本については非推奨となっている。

STLは標準規格に採用される前は、ヒューレット・パッカードの(一時はシリコングラフィックスの)商用ライブラリだった。STLは標準規格の単なる一部分に過ぎず規格書にSTLという表記は見られないが、入出力ストリーム、国際化、デバッグ機能、C言語標準ライブラリ等の、STL以外の部分と区別するために、今でも多くの人がSTLという用語を使っている。

大半のC++コンパイラはSTLを含むC++標準ライブラリの実装を提供している。STLPortのようなコンパイラ非依存のSTLも存在する。様々な目的でC++標準ライブラリを独自に実装しているプロジェクトは他にもある。

C++の標準ライブラリは大きく次のように分けられる。多種多様な実行環境が存在することを考慮して、GUIに関するライブラリは標準に含まれていない。

外部ライブラリ

以下に、C++で広く使われていると思われるライブラリを挙げる。

Boost
次期C++標準とも言われる様々なライブラリの集合。正規表現を扱うBoost.Regexや無名関数(ラムダ計算)を簡潔に記述できるBoost Lambda Libraryなどがある。現標準であるC++11や次期標準であるC++14でも、Boostに存在するライブラリが標準ライブラリに採用されたり、標準ライブラリとして提案された項目がBoostで先行して実装されたりしている。これにより、実際に実装・使用することでの知見が得られ、標準ライブラリとして採用される際に活かされている。
Apache Xerces
C++での主要XMLパーサの一つ。Java版も存在する。
CppUnit
C++でのユニットテストフレームワーク。 クラス毎の動作確認に威力を発揮する。

特徴

C言語に、オブジェクト指向プログラミングをはじめとする様々なプログラミングパラダイムをサポートするための改良が加えられたものといえる。ただし、他のプログラミング言語と違い、旧来のCと同様に手続き型言語としても扱えるという特徴がある。このことから、C++をbetter Cというふうに呼ぶことがある。すなわち、基本的にC言語に対して上位互換性がある。初期のC++はCへのトランスレータとして実装され、C++プログラムを一旦Cプログラムに変換してからコンパイルしていた。

ただし、C++という名称が定まった当初の時期から、C言語とC++との間には厳密な互換性はない[14][15]。当時、Cとの互換性について議論の末、「C++とANSI Cの間には不正当な非互換性はない」という合意が形成されることとなった。そのため、正当な非互換性を巡って多くの議論が発生した[16]。ただし、まだANSIによるC言語の標準規格も策定途中の時期である。

その後、先祖であるC言語のANSIによる標準規格制定時には、関数のプロトタイプ宣言やconst修飾など、C++の機能がC言語に取り入れられることにもなった。C99の出現により、//コメントなどのC++で使われていた便利な機能が加わってCとC++の互換性が高まる一方、別々に審議し、別の時期に発行していることと、開発対象が必ずしも同じでないために利害関係者が異なることによる違いもある​。

次のような多種多様な機能を持っており、言語仕様は大変複雑である。

ここから、よりオブジェクト指向を強化し、「なんでもあり」ではない代わりに分かりやすくスマートな設計を目指した新たな言語(JavaD言語など)が作られることとなった。

Hello, World!

C++はC言語およびそのプリプロセッサの構文をほぼ継承している。以下のサンプルはビャーネ・ストロヴストルップの書籍「The C++ Programming Language, 4th Edition」(ISBN 978-0321563842) の「2.2.1 Hello, World!」に記載されている標準C++ライブラリのストリーム機能を用いて標準出力に出力するHello worldプログラムである[17][18]

#include <iostream>

int main()
{
     std::cout << "Hello, World!\n";
}

書籍でも明記されているが、main()関数で意図的に返り値を返さない手法が使用されている。

演算子と演算子のオーバーロード

C++には四則演算、ビット演算、参照、比較、論理演算などの30を超える演算子がある。メンバーアクセス演算子(..*)のような一部の例外はあるが、大半の演算子はユーザー定義によるオーバーロードが可能である。オーバーロード可能な演算子が豊富に揃えられているためC++を一種のドメイン固有言語として利用できる。またオーバーロード可能な演算子はスマートポインタのような先進的な実装テクニックに欠かせないものとなっている。演算子をオーバーロードしても演算の優先順位は変化せず、また演算子のオペランドの数も変化しない。ただし指定したオペランドが無視される可能性はある。

テンプレート

C++には、ジェネリックプログラミングを実現する機能としてテンプレートが存在する。テンプレートにできる対象は、関数とクラスである。テンプレートは型、コンパイル時定数またはその他のテンプレートによってパラメタライズできる。テンプレートはコンパイル時にインスタンス化(実体化・具現化などとも)される。コンパイラは関数やクラスをインスタンス化するためにテンプレート仮引数を特定の値に置き換える。テンプレートはジェネリックプログラミングテンプレートメタプログラミング、コード最適化などのために利用される強力なツールであるが、一定のコストを伴う。各テンプレートのインスタンスはテンプレート仮引数毎にテンプレートコードのコピーを生成するためコードサイズが肥大化する。コンパイル時に型の情報を削除して単一のテンプレートインスタンスを生成するランタイム型のジェネリクスを実装したJavaなどの言語とは対照的である。

テンプレートとマクロはいずれもコンパイル時に処理される言語機能であり条件に基づいたコンパイルが行われるが、テンプレートは字句の置き換えに限定されない。テンプレートはC++の構文と型を解析し、厳密な型チェックに基づいた高度なプログラムの流れの制御ができる。マクロは条件コンパイルに利用できるが、新しい型の生成、再帰的定義、型の評価などは行えないため、コンパイル前のテキストの置き換えや追加・削除といった用途に限定される。つまりマクロは事前に定義されたシンボルに基づいてコンパイルの流れを制御できるものの、テンプレートとは異なり独立して新しいシンボルを生成することはできない。テンプレートは静的な多態(下記参照)とジェネリックプログラミングのためのツールである。

C++のテンプレートはコンパイル時におけるチューリング完全なメカニズムである。これはテンプレートメタプログラムを用いて実行する前にコンピュータが計算可能なあらゆる処理を表現できることを意味している。

概略すれば、テンプレートはインスタンス化に必要な引数を明確にしなくても記述できるコンパイル時にパラメタライズされる関数またはクラスである。インスタンス化した結果は、テンプレート仮引数に指定した型に特化した形で記述されたコードと全く等価になる。これによりテンプレートは、汎用的かつおおまかに記述された関数及びクラス(テンプレート)と特定の型に特化した実装(インスタンス化されたテンプレート)の依存関係を解消し、パフォーマンスを犠牲にすることなく抽象化できる手段を提供する。

オブジェクト

C++はC言語オブジェクト指向プログラミングをサポートするための改良を加えたものといえる。C++のクラスには、オブジェクト指向言語で一般的な抽象化カプセル化継承多態の4つの機能がある。オブジェクトは実行時に生成されるクラスの実体である。クラスは実行時に生成される様々なオブジェクトのひな形と考えることができる。

なお、C++はSmalltalkなどに見られるメッセージ転送の概念によるオブジェクト指向を採用していない。

カプセル化

カプセル化とは、データ構造を保証し、演算子が意図したとおりに動作し、クラスの利用者が直感的に使い方を理解できるようにするためにデータを隠蔽することである。クラスや関数はC++の基礎的なカプセル化のメカニズムである。クラスのメンバはpublicprotectedprivateのいずれかとして宣言され明示的にカプセル化できる。publicなメンバはどの関数からでもアクセスできる。privateなメンバはクラスのメンバ関数から、またはクラスが明示的にアクセス権を与えたフレンド関数からアクセスできる。protectedなメンバはクラスのメンバおよびフレンド関数に加えてその派生クラスのメンバからもアクセスできる。

オブジェクト指向では原則としてクラスのメンバ変数にアクセスする全ての関数はクラスの中にカプセル化されなければならない。C++ではメンバ関数およびフレンド関数によりこれをサポートするが、強制はされない。プログラマはメンバ変数の一部または全体をpublicとして定義でき、型とは無関係な変数をpublicな要素として定義できる。このことからC++はオブジェクト指向だけでなく、モジュール化のような機能分割のパラダイムもサポートしているといえる。

一般的には、全てのデータprivateまたはprotectedにして、クラスのユーザに必要最小限の関数のみをpublicとして公開することがよい習慣であると考えられている。このようにしてデータの実装の詳細を隠蔽することにより、設計者はインターフェイスを変更することなく後日実装を根本から変更できる [19] [20]

継承

継承を使うと他のクラスの資産を流用できる。基底クラスからの継承はpublicprotectedprivateのいずれかとして宣言する。このアクセス指定子により、派生クラスや全く無関係なクラスが基底クラスのpublicおよびprotectedメンバにアクセスできるかどうかを決定できる。普通はpublic継承のみがいわゆる派生に対応する。残りの二つの継承方法はあまり利用されない。アクセス指定子を省略した場合、構造体public継承になるのに対し、クラスではprivate継承になる。基底クラスをvirtualとして宣言することもできる。これは仮想継承と呼ばれる。仮想継承は基底クラスのオブジェクトが一つだけ存在することを保証するものであり、多重継承の曖昧さの問題を避けることができる。

多重継承はC++の中でもしばしば問題になる機能である。多重継承では複数の基底クラスから一つのクラスを派生できる。これにより継承関係が複雑になる。例えば"FlyingCat"クラスは"Cat"クラスと"FlyingMammal"クラスから派生できる。JavaC#では、基底クラスの数を一つに制限する一方で、複数のインタフェースを継承でき、これにより制約はあるものの多重継承に近い機能を実現できる。インタフェースはクラスと異なりメンバ関数を宣言できるのみであり、関数の実装やメンバ変数は定義できない。JavaとC#のインタフェースや抽象クラスはC++の抽象基底クラスと呼ばれる関数宣言のみを持つクラスに相当する。JavaやC#の継承モデルを好むプログラマは、非抽象クラスからのみクラスを派生させる方法を選択できる。この場合は抽象基底クラスのメンバ関数を必ず明示的に定義しなければならず、またこのクラスを継承することはできない。

多態

多態(ポリモーフィズム)はよく多用されているインターフェイスの機能であり、様々な状況下でオブジェクトに異なる振る舞いをさせることができる。

C++は静的な多態動的な多態の両方をサポートする。コンパイル時に解決される静的な多態は実行時には考慮されないのに対し、ランタイム時に解決される動的な多態はパフォーマンス的に不利である。

静的な多態

関数のオーバーロードは名称が同じ複数の関数を宣言できる機能である。ただし引数は異なっていなければならない。関数は引数の型や数で区別される。同名の関数はコードの文脈によってどの関数が呼ばれるのかが決まる。関数の戻り値の型で区別することはできない。

関数を宣言する際にプログラマはデフォルト引数を指定できる。関数を呼び出すときに引数を省略した場合はデフォルト引数が適用される。関数を呼び出すときに宣言よりも引数の数が少ない場合は、左から右の順で引数の型が比較され、後半部分にデフォルト引数が適用される。たいていの場合は一つの関数にデフォルト引数を指定するよりも引数の数が異なる関数をオーバーロードする方が望ましい。

C++のテンプレートではより洗練された汎用的な多態を実現できる。特にCuriously Recurring Template Patternにより仮想関数のオーバーライドをシミュレートした静的な多態を実装できる。C++のテンプレートは型安全かつ チューリング完全であるため、 テンプレートメタプログラミングによりコンパイラに条件文を再帰的に解決させて実行コードを生成させることにも利用できる。

動的な多態

派生

基底クラスへのポインタ変数及び参照は、正確に型が一致するオブジェクトだけでなく、その派生クラスのオブジェクトを示すことができる。これにより配列やコンテナは複数の型へのポインタを保持できる。ポインタ変数は実行時に値が割り当てられるためこれは実行時の話である。

dynamic_castは基底オブジェクトから派生オブジェクトへの変換を安全に行うための演算子である(派生オブジェクトから基底オブジェクトへの変換ではキャストは必要ない)。この機能は実行時型情報 (RTTI)に依存している。オブジェクトが特定の派生オブジェクトであることがあらかじめわかっている場合はstatic_castでキャストすることもできる。static_castは純粋にコンパイル時に解決されるため動作が速くRTTIを必要としない。

仮想関数

基底クラスの関数を派生クラスでオーバーライドした場合、実際に呼び出される関数はオブジェクトの型によって決定される。派生クラスによってオーバーライドでされるのは引数の数や型が同じ関数である。基底クラスのポインタのみが与えられた場合、コンパイラはオブジェクトの型をコンパイル時に特定できず正しい関数を呼び出せないため、実行時にこれを特定する。これをダイナミックディスパッチと呼ぶ。仮想関数やメソッド[21]により、オブジェクトに割り当てられた実際の型に従って、最上位の派生クラスで実装した関数が呼び出される。一般的なC++コンパイラは仮想関数テーブルを用いる。オブジェクトの型が判明している場合はスコープ解決演算子を利用して仮想関数テーブルを使わないようにバイパスすることもできるが、一般的には実行時に仮想関数の呼び出しを解決するのが普通である。

標準のメンバ関数に加え、オーバーロードした演算子やデストラクタも仮想関数にできる。原則的にはクラスが仮想関数を持つ場合はデストラクタも仮想関数にすべきである。コンストラクタやその延長線上にあるコピーコンストラクタはコンパイルされた時点でオブジェクトの型が確定しないため仮想関数にできない。しかし、派生オブジェクトへのポインタが基底オブジェクトへのポインタとして渡された場合に、そのオブジェクトのコピーを作らなければならない場合は問題が生じる。このような場合はclone()関数(またはそれに準じる物)を仮想関数として作成するのが一般的な解決方法である。clone()は派生クラスのコピーを生成して返す。

= 0を関数宣言の閉じ括弧とセミコロンの間に挿入することによりメンバ関数を純粋仮想関数にできる。純粋仮想関数を持つクラスは純粋仮想クラスと呼ばれ、このクラスからオブジェクトを生成することはできない。このような純粋仮想クラスは基底クラスとしてのみ利用できる。派生クラスは純粋仮称関数を継承するため、派生クラスのオブジェクトを生成したい場合は全ての純粋仮想関数をオーバーライドして実装しなければならない。純粋仮想関数を持つクラスのオブジェクトを生成しようと試みるようなプログラムは行儀が悪い。

テンプレート

型消去と呼ばれるテンプレートを活用して動的な多態性を実現する手法が存在する。この手法はC++の標準ライブラリでもstd::functionstd::shared_ptrの削除子で採用されている。いずれも、コンストラクタや代入演算子で(一定の条件を満たす)任意のオブジェクトを実引数として渡せるようにすることから多態性を実現している。

単一行コメント

C99の制定前、C言語とC++との分かりやすい差異として、// で始まり改行で終わる、単一行コメントの有無があった。

単一行コメントはもともと、C言語の祖先にあたるBCPLに含まれていた仕様である。現在のC++のコンパイラの多くがC言語のコンパイラとしても使えるようになっているのと同様に、C言語が生まれて間もない頃は、C言語に加えB言語やBCPLのコンパイルができるコンパイラが用いられていた。それらコンパイラは、C言語のソースであってもBCPLと同様に単一行コメントが使用できるよう独自の拡張がなされていたため、現在ではC99の制定によって正式に単一行コメントがサポートされるようになった。

C++ソースコードの処理とパーサ

LALR(1)のような旧式のパースアルゴリズムを用いてC++のパーサを記述することは比較的難しい[22]。その理由の一つはC++の文法がLALRではないことである。このため、コード分析ツールや、高度な修正を行うツール(リファクタリングツールなど)は非常に少ない。この問題を取り扱う方法としてLALR(1)でパースできるように改良されたC++の亜種(SPECS)を利用する方法がある。GLRパーサのようにより強力でシンプルなパーサもあるが処理が遅い。

パースはC++を処理するツールを作成する際の最も難しい問題ではない。このようなツールはコンパイラと同じように識別子の意味を理解しなければならない。従ってC++を処理する実用的なシステムはソースコードをパースするだけでなく、各識別子の定義を正確に適用し(つまりC++の複雑なスコープのルールを正確に取り扱い)、型を正しく特定できなければならない。

いずれにせよC++ソースコード処理ツールが実用的であるためには、GNU GCCVisual C++で使われているような、様々なC++の方言を取り扱えなければならず、適切な分析処理やソース変換やソース出力などが実装できなければならない。GLRのような先進的なパースアルゴリズムとシンボルテーブルを組み合わせてソースコードを変換する方法を利用すればあらゆるC++ツールを開発できる。

互換性

その言語文法の複雑さゆえ、C++規格に準拠したコンパイラを開発するのは一般的に難しい。20世紀末から何年にも渡りC++に部分的に準拠した様々なコンパイラが作られ、テンプレートの部分特殊化などの部分で実装にばらつきがあった。中でも、テンプレートの宣言と実装を分離できるようにするためのexportは問題のキーワードの一つだった。exportを定義したC++98規格がリリースされてから5年後の2003年前半にComeau C/C++が初めてexportを実装した。2004年にBorland C++ Builder Xexportを実装した。これらのコンパイラはいずれもEDGフロントエンドをベースにしていた。大半のコンパイラで実装されていないexportは多くのC++関連書籍(例えば"Beginning ANSI C++", Ivor Horton著)にサンプルが記されているが、exportが記載されていることによる問題は特に指摘されていない。GCCをはじめとするその他のコンパイラでは全くサポートしていない。Herb SutterはC++の標準規格からexportを削除することを推奨していたが[23]、C++98では最終的にこれを残す決定がなされた[24]。結局、C++11では実装の少なさ・困難さを理由に削除された。

コンパイラ開発者の裁量で決められる範囲を確保するため、C++標準化委員会は名前修飾例外処理などの実装に依存する機能の実装方法を決定しないことに決めた。この決定の問題は、コンパイラが異なるとオブジェクトファイルの互換性が保証されない点である。特定の機種やOSでコンパイラの互換性を持たせ、バイナリレベルでのコード再利用性を高めようとするABI[25]のような非標準の規格もあり、一部のコンパイラではこうした準規格を採用している。

2015年現在のメジャーなC++コンパイラ(gcc,Clang,Intel C++ Compiler,Microsoft Visual C++など)の最新版はC++11規格にほぼ準拠しており、特にClangは2013年4月時点で全機能を実装完了した [26] [27]。ただしマイナーアップデートとなるC++14を含めると、処理系間でのばらつきは依然として存在する。

C言語との互換性

C++は基本的にC言語の上位互換であるが、厳密には異なる[28]。C言語で記述された大半のプログラムはC++でコンパイルできるように簡単に修正できるが、C言語では正当でもC++では不正になる部分や、C++とは動作が異なる部分が若干存在する。

例えば、C言語では汎用ポインタvoid*は他の型へのポインタに暗黙的に変換できるが、C++ではキャスト演算子によって変換を明示する必要がある。またC++ではnewclassといった数多くの新しいキーワードが追加されたが、移植の際に元のC言語のプログラムでそれらが識別子(例えば変数名)として使われていると、問題になる。

C言語の標準規格であるC99やその後継C11ではこうした非互換性の一部が解決されており、//形式のコメントや宣言とコードの混在といったC++の機能がC言語でサポートされている。その一方でC99では、可変長配列、複素数型の組み込み変数、指示初期化子、複合リテラルといった、C++でサポートしていない数多くの新機能が追加された[29]。C99で追加された新機能の一部はC++11に反映され、次期C++1yに対してもC99やC11との互換性を向上される提案が行われている。また、可変長配列や複素数型などのC99に追加された機能の一部はC11でオプションとなった[30]

C++で書かれた関数をC言語で書かれたプログラムから呼び出す、あるいはその逆を行なう場合など、C言語のコードとC++のコードを混在させるためにはCリンケージを利用する必要があり、関数をextern "C"で個別に修飾するか、extern "C" { ... }のブロックの中で宣言しなければならない。また、関数引数や戻り値などのインターフェイスはC言語互換形式に合わせる必要がある。Cリンケージを利用した関数については、C++名前修飾がされず、名前修飾に依存している関数オーバーロード機能は利用できない。

C/C++の相互運用性が確保されていることで、慣れ親しんだC言語標準ライブラリ関数の大半をC++でもそのまま利用し続けることができるということはC++の大きなメリットのひとつである。

主なC++処理系

脚注

  1. 『プログラミング言語C++』第4版、pp.12-13。
  2. 『C++の設計と進化』、pp.152-153。
  3. 『プログラミング言語C++』第4版、p.11。
  4. Bjarne Stroustrup's FAQ - When was C++ invented?” (English). . 2006閲覧.
  5. Bjarne Stroustrup (1990). The Annotated C++ Reference Manual. Addison-Wesley Professional. ISBN 978-0201514599. 
  6. Bjarne Stroustrup; Margaret A. Ellis 『The Annotated C++ Reference Manual』 足立高徳、小山裕司、シイエム・シイ、2001年。ISBN 978-4901280396。
  7. ISO/IEC 14882:1998
  8. ISO/IEC 14882:2003
  9. ISO/IEC TR 19768:2007
  10. ISO/IEC 14882:2011
  11. ISO/IEC 14882:2014
  12. https://www.iso.org/standard/68564.html
  13. We have C++14! : Standard C++
  14. Koenig, Andrew; Bjarne Stroustrup (1989年5月11日). “C++: as close as possible to C – but no closer (PDF)” (英語). . 2016閲覧.
  15. Stroustrup, Bjarne. “Stroustrup: FAQ Is C a subset of C++?” (英語). . 2016閲覧.
  16. 『C++の設計と進化』、pp.124-125。
  17. Bjarne Stroustrup (2000年). The C++ Programming Language, Special Edition, Addison-Wesley, 46. ISBN 0-201-70073-5. 
  18. Open issues for The C++ Programming Language (3rd Edition) - このコードはストロヴストルップ自身による訂正文からの引用(633ページ)。std::endl'\n'に改めている。またmain関数がデフォルトで0を返す件についてはwww.research.att.com及びwww.delorie.com/djgpp/ を参照されたし。このデフォルト仕様はmain関数のみであり他の関数にはない。
  19. (2004) C++ Coding Standards: 101 Rules, Guidelines, and Best Practices. Addison-Wesley. 
  20. (1997) Industrial Strength C++. Prentice Hall. ISBN ISBN 0-13-120965-5. 
  21. Stroustrup, Bjarne (2000). The C++ Programming Language, Special Edition, Addison-Wesley. ISBN 0-201-70073-5. “A virtual member function is sometimes called a method. (仮想関数のことをメソッドと呼ぶ場合がある)” 
  22. Andrew Birkett. “Parsing C++ at nobugs.org”. Nobugs.org. . 2009閲覧.
  23. Why We Can’t Afford Export (PDF, 266 KB)
  24. Minutes of J16 Meeting No. 36/WG21 Meeting No. 31, April 7-11, 2003” (2003年4月25日). . 2006閲覧.
  25. C++ ABI”. . 2006閲覧.
  26. 後藤大地 (2013年4月22日). “LLVM Clang、C++11にフル対応”. マイナビニュース. . 2013閲覧.
  27. GCC 4.8.1 - C++11全実装バージョン”. Faith and Brave - C++で遊ぼう (2013年6月7日). . 2013閲覧.
  28. Bjarne Stroustrup's FAQ - Is C a subset of C++?”. . 2008閲覧.
  29. C9X -- The New C Standard”. . 2008閲覧.
  30. C言語の最新事情を知る: C99の仕様 - Build Insider

参考文献

  • Stroustrup, Bjarne 『プログラミング言語C++』 ロングテール、長尾高弘訳、アジソン・ウェスレイ・パブリッシャーズ・ジャパン , アスキー (発売)〈アスキーアジソンウェスレイシリーズ〉、1998年(原著1997年)、第3版。ISBN 475611895X。
  • Stroustrup, Bjarne 『プログラミング言語C++』 柴田望洋訳、SB Creative、2015年(原著2013年)、第4版。ISBN 978-4-7973-7595-4。
  • Stroustrup, Bjarne 『C++の設計と進化』 επιστημη監修、岩谷宏訳、ソフトバンククリエイティブ、2005年(原著1994年)。ISBN 4797328541。

関連項目

外部リンク

テンプレート:C++