C++入門最前線――21世紀のC++の学び方

もう8年以上たっているというのに、このタイトルは(ry

プログラミング初心者のC++の学習方法というと、

  1. まずC言語と共通の機能を学ぶ。
  2. 次にクラスとオブジェクト指向プログラミングを学ぶ。

という古典的な方法が有名だけど、正直なところ古典的すぎてあまりよろしくないと思う、というのがこのエントリの主旨だ*1

C言語(ないしC++C言語的な側面)は学ぶ価値はあるけど絶対に学ばなくてはならないわけではない。というか、正直なところ「人生で初めて触れるプログラミング言語」という観点では色々と不味い点が多い言語だと思う。本質的な所に辿りつくまでの道程が長く険しいものになりやすいのだ*2

それに、これは有名な話だけど、C++は特にオブジェクト指向専用というわけではない。開発者であるストラウストラップ本人が、「C++ Programming Styles and Libraries (PDF)」の中でC++がサポートするパラダイムとして、

を挙げているぐらいだし、STLやTR1(Technical Report 1)の機能を使うと限定的ながらも関数型言語的なプログラミングもできる。Boostを大々的に使うともっと凄いことになるらしい*3

だから、「C++なのでクラスとオブジェクト指向」と限定するべき理由は無い。

もちろん件の古典的方法にもメリットがあって、それは例えば、

という点だ*5。特に仕事でC++を使う場合は、こういった点も重要になってくる。

問題は、この学習方法は地味で且つ時間が掛かることだ。

まず「C言語と共通の機能を学ぶ」というのは、ひたすら地味な作業を長々と続けるのと同義だ。試しにC言語で何かツールを書いてみると分かる。C言語はコンパクトすぎて、標準の機能だけでは何かやるのに時間が掛かるのだ*6。もちろんそれはツールとしてのC言語の強みを裏返した結果なんだけど、しかし学習者としては地味な内容が長々と続くことになり、正直厭きてしまう。例え学ぶのがC++でも、「C言語と共通の機能」という括りなら、結果は同じだ。

高機能且つ複雑なアプリケーションが身近に溢れている現在、そんなアプリに慣れているプログラミング未経験者にとって、普通のアプリケーションと言えば身近に溢れている「高機能且つ複雑なアプリケーション」だ。しかしC言語でそのようなアプリを実装する事は、不可能ではないが非常に大変だ。大抵の人は、まず途中で放棄してしまうだろう。

当然ながら「高機能且つ複雑なアプリケーション」を目指さないという手もある。例えばUnixの世界で昔から使われてきたフィルタを題材とするなどして、敷居を下げるわけだ。しかし問題は、例え簡単なフィルタでも、C言語で実装するには意外と労力がいるという点だ。だから大抵のプログラマC言語よりもgawkPerlPythonRubyなどでフィルタを自作する。

次に、プログラミング初心者にいきなり「クラスとオブジェクト指向プログラミング」を学ばせるのは問題がある*7。というのもこれらの機能は、ある程度大きなソフトを書いてみないと有り難味が分からないからだ*8

例えば私の場合、数百行程度の大きさのコンソールアプリを実装する場合、関数や構造体を自分で定義することは頻繁にあるけどクラスを自分で定義することは殆どない。その程度ならクラスが不要であることが多いからだ。しかし数千行以上のライブラリを実装するような場合、自分でクラスを定義するだろう*9。その方が便利だからだ。

これは、私がCプログラマながらもある程度以上の大きさのソフトウェアを実装した経験があるから分かる話だと思う。しかしプログラミング初心者に直ぐにそれが分かるとは思えない*10。そんな、何で必要なのかイマイチ分からないものを学ぼうとしても、動機に欠ける分だけ学習効率は落ちるはずだ*11

初心者が「ポインタって何に使うの? おいしいの?」と疑問を抱くのに対して、ある程度熟達したCプログラマが「ポインタがないと生きていけないよ!」と叫ぶ――その落差と似たようなものが「クラスとオブジェクト指向」のルーキーとベテランの間にもあって、その溝を埋めるには、多分そこそこの大きさのプログラムを書いて痛い目に遭うのが一番早い。

最後に、この学習方法では「既に存在する便利な機能」について学ぶ機会が少ない。というのも、この方法で学ぶC++のサブセットには、多くの場合、

しか含まれていない。便利な外部ライブラリを使わなければ、残りはCの標準ライブラリ相当の機能ぐらいだろう。そう、文字列型というべき機能は無いし、配列の大きさを動的に変えることはできないし、連想配列もない。

しかし現実にはC++の標準ライブラリにstd::stringがあるし*12STLには豊富なコンテナやアルゴリズムが用意されている。std::vectorを使えば、配列のサイズを超える数のデータに悩むことはない*13。std::mapは連想配列のように使える。なのに、それらの便利な道具について殆ど学ばないなんて、物凄く損な話だ。

長々と問題点を挙げてきたけど、ではどうするべきか? 思うに、そろそろC言語から離れてC++らしい入門方法を用意するべきなのだ。具体的には、最初からC++標準ライブラリの機能を提示するのだ。文字列にはstd::stringを使い、配列と一緒にstd::vectorやstd::mapなどのコンテナを紹介すると同時にアルゴリズムも幾つか紹介する。エラーの捕捉には例外も使い、キャストはC++スタイルで行う。ポインタは後回しにして、まずは参照だ。クラスやオブジェクト指向も後回しだ。

過激だろうか? そうは思わない。こういう方針のC++入門書を見たこともあるし、何より比較的短時間で自分用の実用的なツールを書けるようになるという利点がある。利点? そう、プログラミング初心者にとっては利点だ。自分が書いたプログラムが目の前で動くこと以上に、プログラミングの学習意欲をかき立てることがあるだろうか?

簡単でもよいから何かプログラムを書けるようになれば、ちょっとした自分用のツールを自作しようと考える人も出てくるだろう。そんな時、便利なライブラリを知っているか否かの差は大きい。簡単にできそうなことなら手を出す人は多いだろうけど、難しそうだったり手間がかかりそうなことに手を出す人は少ないはずだ。便利なライブラリは「難しそうだったり手間がかかりそうなこと」を覆い隠して簡単な風に見せてくれるし、実際に簡単になることが多い*14。しかも標準ライブラリなら導入の手間も不要だ。ファイルの先頭にちょっとした一文を付け加えるだけで済む。

例えばRubyを学ぶ場合、クラスを定義する方法より先にArray/File/Hash/Regexp/Stringなどの便利な組込みクラスの使い方を学んだ方が、実用的なスクリプト*15を書けるようになる。勿論そこから先に進むなら、クラスを定義する方法を学ぶことになるだろう。だけど既に学んだことが無駄になることはない。

では先にクラスを定義する方法を学んだ場合はどうだろうか? 害にはならない。だけどごく短いスクリプトでは、自前のクラスを用意するメリットは薄い。それに、やはりよく使用するArray/File/Hash/Regexp/Stringあたりのクラスの使い方を学ばないと、実用的なスクリプトを思うように書けないのだ。

これはC++でも同じだ。更に悪いことに、C++にはクラスやオブジェクト指向関連の機能が山のようにあるし*16、落とし穴も多い。学習コストが高いのだ。苦労して覚えたそれらの知識は無駄にはならないけど、即効性が低い。何かちょっとしたツールを作る時、クラスの定義方法よりもSTLやstd::stringの知識の方が役に立つことが多いのだ。

正直なところ、最初のうちはSTLを活用した手続き型プログラミングでも構わない*17。必要になってからクラスについて学んでも十分に間に合うし、むしろ必要になってから学んだ方が覚えは早いだろう。

かつてはテンプレートがらみで色々とトラブルが絶えなかった処理系も多かったけど、今ではそれも解消されつつある。だから、テンプレートを使ったC++の標準ライブラリを普通に使う分には、何も問題はないはずだ。STL等を最初から全面に押し出しても構わないと思う。

問題は、STLを全面に押し出したC++の入門書って『Accelerated C++―効率的なプログラミングのための新しい定跡 (C++ In Depth Series)』ぐらいしか思い浮かばなくて、且つ良い本ではあるけど手放しで他人に薦めることができる内容ではない、ということ。初心者向けとしては、ちょっと文字が多すぎだと思う*18

*1:ついでにこのエントリの内容自体も古典的。例えば標準C++を新しい言語として学ぶを参照。

*2:なので、私はC言語が好きな自称Cプログラマだけど、あまり他人には薦めようとは思わない。

*3:但しBoostを使ったことはないので、本当のところは不明。本などでBoostを使ったサンプルを眺めた限りでは、結構関数型っぽいことができそうではある。

*4:例えばC言語で実装された既存のライブラリを使うとか。

*5:まあ歴史的な経緯も色々とあるんだろうけど。

*6:便利な外部ライブラリも沢山あるけど、それだって使えるように色々と準備しなくちゃならない。それは手間だし、あまり初心者に薦められない。

*7:「いきなり」という表現は微妙かもしれないけど、例えば「C言語 --> C++」という流れの入門書で、クラスとオブジェクト指向の話題に入る前に試しにそこそこ複雑なアプリケーションを書かせるような本を見たことがない、ということ。

*8:ここではC++を前提に議論している点に注意すること。これが例えばRubySmalltalkだと話は変わってきて、比較的早い段階から「クラスとオブジェクト」ないしそれに近いイメージが出てきても問題ないと思う。

*9:もっともオブジェクト指向がよく分からない人なので、抽象データ型的な使い方Onlyだけど。

*10:まあ中には分かる人もいるだろうけど、多分ごく少数だと思う。というかそんな人がいたら、正直その人が羨ましい。

*11:この点についてもC++を前提に議論していることに注意。例えばRubySmalltalkでは話は変わってくると思う

*12:GUIツールキットとの相性があるので、例えばMFCならCStringを使うことになるけど。

*13:もちろんメモリ不足へのケアは必要だけど。

*14:もちろん便利なライブラリが覆い隠している中身を知っておく必要があるケースは多々あるのだけど、別に最初から知っていなければならない訳じゃない。

*15:ちなみにここではテキスト処理用のフィルタを念頭においている。

*16:オライリーの『C++プログラミング入門』のように、オブジェクト指向関連の機能だけで1冊の本が書ける程度のボリュームがある。

*17:というか、それこそがbetter Cとしてあるべき姿だと思う。

*18:その分、図が少ない。