SoftwareDesign2012年9月号に記事を書かせていただきました & erattaのお詫び

遅い報告になってしまいましたが、タイトルのとおり、SoftwareDesign 2012年9月号に記事を書かせていただきました。

SoftwareDesignトップページ
該当号もくじ

特集「C言語のポインタは必要ですか?」の2番目の記事「Part2:ポインタの壁の克服の仕方」を書かせていただいております。
テーマがテーマだけに、「C言語 ポインタ完全制覇」のダイジェスト的なものになっている面はありますが、はてなブックマークでも定期的にCのポインタが話題になるようですから、今こういう記事を書くことにも相応の価値はあるのではないかと思っています。
また、ISO C99についても多少言及しました。

そして、早々にミスが見つかってしまいました。申しわけありません。

p.30 「空の[]について」の上の章、下から6行目
誤)
「intの配列(要素数3)の配列(要素数5)」と読めます。
正)
「intの配列(要素数5)の配列(要素数3)」と読めます。

p.31 図1
誤)
int a[5][3]という配列において
正)
int a[3][5]という配列において

多次元配列の読み方のところですので、今回の記事において、かなり重大なミスかと思います。
大変申しわけありませんでした。

Cの宣言は英語順で読もう、という話

Cでのポインタの読み方

上記のページ、現時点ではてなブックマークが1241ついています。同趣旨のことを私は1998年に以下のページに書きました。
配列とポインタの完全制覇
こちらのはてブ数は212…… きいいっ! 悔しい!!

などという話はさておき。

上記ページに関連してだと思うのですが、Twitterで@kinabaさんが以下のようにつぶやかれておりました。



『という方針のCの入門記事』ということであれば、WebではないのでURLは貼れませんが、たとえば柴田望洋先生の「秘伝 C言語問答 ポインタ編」*1には以下の記述があります(p.22)。

ここで、下のように考えると、int x;の部分が*ptrに相当すると考えられますね。


int x ;
int *ptr ;
――*ptrはint型変数であると言っているように解釈できますね。

で、実のところこれを意識した上で、私は「C言語 ポインタ完全制覇」にこう書きました(p.38)。

別の考え方として、


int *hoge_p;
という宣言について、hoge_pがhogeを指しているとき、*hoge_pはhogeと同じように使えますから、

ほらほらhoge_pに*を付けると、int型の変数hogeと同じように使えるんだよね。この宣言はつまり、hoge_pに*を付けたものがint型だという意味なんだよ

という説明をする人もいます。
この考え方は、確かにそれなりに通用するのですが(たとえば配列でも同じようにいえる)、では、


int *&hoge;
と書くと、int型の変数としてhogeが宣言できるのでしょうか?*2――やってみるとわかりますが、これはシンタックスエラーです。
それに、この考え方は、宣言の中にconstが割り込んでくると破綻しますし(式の中じゃconstは書けない)、関数へのポインタの宣言でも問題が発生します。

『関数へのポインタの宣言でも問題が発生します』について補足します。上記のような説明は、『使う時の構文と宣言の構文が似るようにという方針で設計されてる』という前提に従うわけですから、たとえばint *a;という宣言があったとき、これを『使う時』に*aと書くとint型になるよね、ということを前提としています。では関数へのポインタのときにはどうか。int (*func)(void);という宣言があったとき、これを『使う時』、みなさん(*func)()のように書くかというと*3、たいていfunc()と書くのではないでしょうか。少なくともこのケースでは、「使う時」の書き方と宣言がずれています。

実のところ関数へのポインタを持ち出すまでもなく、int *a;と宣言した変数を使うときにはa[i]と書くことなどは普通にあるのですから、『使う時の構文と宣言の構文が似るようにという方針』がさして役に立つとは思えません。『使う時』というのは式の中で使うということでしょうが、その式の中では配列がポインタに読み替えられるとか、関数が関数へのポインタに読み替えられるとか、関数定義の仮引数の宣言においてのみ最外周のはポインタを意味するとか、謎の規則がいっぱいある以上、結局、"a ptr to func returning ptr to func returning char"のような『コンパイラの内部表現っぽい表示』を経由しない限り、理解には至らないと私は思います。

最初に紹介したページのブクマコメントには、『実際にこんなコード書かれたらキレタ方ががいいと思う』とか『おとなしく typedef 使おうず』といったコメントがつきました。確かにsignal()みたいな関数はちょっと特殊な例かと思いますし、適切にtypedefを使ったり構造体をかませたりするほうがよいのは確かです。ただし、typedefは結局『コンパイラの内部表現っぽい表示』の一部に名前を付けてコピペする機能でしかないわけで、まずは宣言をきちんと読めていないと結局使いこなせないのではないでしょうか((そしてtypedefは構文上「記憶クラス指定子」なので、typedef自体を理解するのもたぶん結構難しい))。

さて。最後は宣伝しますよ。

「Cの宣言は英語で読め」とか、「配列は式の中ではポインタに読み変えられる」とか、「添字演算子は配列とは無関係だ」とか、「Cには多次元配列は存在しない」とか、役に立つ記述でいっぱいですよ!!

10年前の本ですが、今回「Cでのポインタの読み方」というページがホットエントリに上がってきたということは、たぶんまだこういう本の需要はあるのでしょう。そして上記ページとかこういう本とかに需要があるということ自体が、「結局のところコンパイラの内部表現っぽいレベルまで理解しないとCを使いこなせない」ということを意味しているのだと思います*4

*1:この本は何度も改版されています。「秘伝C言語問答 ポインタ編 第2版」→「図解C言語 ポインタの極意」→「詳解 C言語 ポインタ完全攻略」でいいのかな。ただし、私が持っているのは「新版 秘伝 C言語問答 ポインタ編」のみです。

*2:実はCを学び始めた頃、試したことがあります。私。

*3:書けますし動きますが

*4:「ポインタ完全制覇」では、Cの型について連結リストの図で説明しています。まさにコンパイラの内部表現ですが、それが必要だと私は判断しました。

祝! はてなブックマーク改悪状態からおおむね復帰

3ヶ月放置したら広告が出るんだったっけ、と思ってたら本当に出たので間に合わせの記事ですが。

はてなブックマークの各エントリのページに「人気」「新着」のタブがつき、「新着」を選べば、コメントつきのブクマの全件を一覧表示できるようになりました。かつ、一度「新着」を選べばブラウザが覚えていてくれるので、これならほぼ以前のはてブと同様の感覚で使うことができます。
最初、「新着」タブで表示されているのが「コメントつきのブクマ全件」であることに気付かずに、「まあ改悪かよ!」と思ったのですが、これなら許容範囲です。

正直、本当は元に戻してほしかったですが、一応喜んでおきます。

「はてブ元に戻して」運動実施中です。

ご存知の通り、4/5にはてなブックマークが改悪されました。

はてなブックマークのエントリーページを改良しました - はてなブックマーク日記 - 機能変更、お知らせなど

上のページのはてブ
はてなブックマーク - はてなブックマークのエントリーページを改良しました - はてなブックマーク日記 - 機能変更、お知らせなど

この変更により、ブックマークの一覧性が失われてしまいました。現状、私はブクマのページを表示するたびに毎回一番下までスクロールし、「すべてのブックマークを見る」をクリックしている、という有様です。面倒です。
この変更には、「早期に☆がついたブクマコメントしか読まれなくなる」という弊害もあります。この仕様だと「平日の昼間っからネットをうろうろしてせっせとブクマコメントを書いている人たち」が有利になるわけで、「ネット上で声の大きい人」の声をさらに大きくするだけでしょう。

というわけで、いまさらではありますが、私は最近はブックマークするたびに「はてブ元に戻して」というタグをつけています。
はてなブックマーク - kmaebashiのブックマーク

よろしければ皆様もご一緒に。

寄付で売名もできないこんな世の中じゃ

id:Dr-Seton さんのところのエントリに便乗し、日本赤十字義援金を送ってきました。
皆様にお願い - シートン俗物記

私が確認した時点で1355ブクマだったので、それ×100円分。今はなぜかひとつ減って1354ブクマになっていますが。最初の24時間くらいはブクマ数がむくむく伸びていて、それはドキドキしましたとも。最終的な金額は、まあ「ただちに生活に影響がでるものではない」金額ですのでご心配なく。

それにしても、今回のシートンさんのところのブックマークコメントでもそうですが、この手の話になるとやれブクマ稼ぎだの黙ってやれだのの声が出てきて閉口します。というより私がこれに便乗して募金する気になったのは、id:temtanさんの以下のコメントが原因です。

temtan (´Д`)y-~ いいからとっとと自分が出来る募金をしろよ。それとも自分の自己顕示欲を満たさないと禄に募金もできねーのか?ありえないとか言ってる癖に大怪我を防ぐ予防線張ってるのも見事に糞 2011/03/31

「見事に糞」とまで言いますか。

メタブクマではこれ。
はてなブックマーク - はてなブックマーク - 皆様にお願い - Dr-Seton’s diary

temtan (´Д`)y-~ わかった、「募金を利用して自分の自己顕示欲を満たしたいけど出した金額に見合った満足度じゃないと嫌だし、自分が許容できない金額も出したく無い」って見えるからむかつくんだ.

自己顕示欲だろうが売名だろうがそれで被災者の方が助かるのならよいのでは、と思いますし、そもそも私には自己顕示欲を満たそうとしたり売名したりブクマ稼ぎしたりすることの何が悪いのかがわかりません*1。それなりの金額を募金するのなら、金額を含め、公開でやったほうが「あの人があんなに募金したのか。じゃあ私も募金しよう」的な効果が期待できるはずです。もちろんそれの度が過ぎて、「募金しない奴は非国民」みたいな同調圧力が高まってしまったら息苦しいですが、現状、募金しているほうが『見事に糞』と罵られている状態です。これはいくらなんでもおかしい。

実のところ私は、被災者支援などということは本来税金で行うべきことで、義援金のようなものをあまり当てにするようになってしまったら困ると思います。それもあって、あまり募金を人に勧めようとは思わないのですが、募金する方を非難するのはさらにどうかしている。それが宣伝や売名と紐付いていたとしても、それによるマイナス面は何もない。

というわけで私も宣伝するよ!

ネタがネタだけに興味を持つ人は限られるのかもしれませんが、型なし言語、静的型付け言語それぞれについて実際に言語を作りながら解説していますから(ソースはWebからダウンロードできます)、言語作りに興味のある方は一読されても損はないと思います。正直、そんなに売れてないので私としては是非売れてほしい本です…… よろしくお願いいたします。

その他、現在ふつうに入手可能な既刊本が以下。


こっちは現在amazonに在庫なし?

追記:今回件のエントリーをブクマされた方に言いたいのですが、ブクマしたことで100円募金した気にはならないでくださいね。だって募金してないし。
追記2:今回の件でシートンさんを批判したのはtemtanさんだけじゃないですが、一番言葉が汚いと思ったので代表として選択しても問題ないと判断。

*1:ブクマ稼ぎについては、spamになってしまえば問題ですが、今回のケースではそれに当たらないでしょう。

「カレー無料法」は思考実験にも何にもなってない

mojixさんの記事:
もしも「カレー無料法」ができたら - モジログ

いやさ、mojixさんはどうせいつもこんな感じなのだけども、賞賛しているブクマコメントが多いのに引いた。
はてなブックマーク - もしも「カレー無料法」ができたら - モジログ

これを「思考実験」と言うのなら、ある状況を仮定したとき次にどのような状態になるのかを論理的に説明できなければいけないでしょう。この例では、
『「お金のない人にも、せめてカレーくらい食べさせてあげよう」という趣旨のもと「カレー無料法」が制定され、政府が一食500円の補助金を出して飲食店にカレーを無料で提供させる』
という状況を仮定しています(その前の、補助金なしでカレーを無償提供させる例はあまりにも非現実的なので割愛)。

もし本当にこんな状況になったら何が起きるか。mojixさんの言うように、みんなカレーばかり食べるようになって他の飲食店が壊滅するのか。

んなわきゃない。当たり前だが、500円の補助金で無料で提供できるカレーには、500円以上の価値はない。店が架空請求でもしない限り、500円の補助金をもらうためには、材料費と人件費をかけてカレーを作り、広告し、店舗を構えて、カレーをお客さんに実際に食べてもらわなければならない。よって、売値で500円以下のカレーでなければ商売にならない。「(売値500円以下の)カレーならただで食えるとしても、金払ってもいいから他のものを食べたいと考える人」は別の店を選ぶはずだ。市場原理ってそういうもんだろう。

牛丼屋のように、もともと単価の安い店とは競合するかもしれない。しかし毎日カレーじゃ誰だって飽きるし、タダのカレーを提供する店はホームレスさんとかが主な客層になりそうだから*1、ある程度お金のある人はそういう店は避けるだろう。ホームレス向けの炊き出しは、別に「ホームレスであることの証明」を求めたりはしないから、たとえば私が列に並んだって何か食べ物をもらえるんだろう。だからって私は並ぼうとは思わない。そういう話。

ところで、上記仮定では「補助金が500円であること」が前提になっている。これは、もともとの想定が、「お金のない人にも、せめてカレーくらい食べさせてあげよう」という趣旨の法律だから、まさか補助金を3000円にするわけにはいかなかった、ということだろう。いやさもちろん実際には500円でも世論の支持は得られるわけがないんだけどそれはさておき。もしこれが、「カレー大好きな王様が、何が何でも国民にカレーを広めようと、カレーに限り1食あたり3000円の補助金を出した」ということだと話が変わってくる。補助金が3000円出るんなら、本来1000円のカレーを出しても2000円余計に儲かる。カレーばかりじゃ客も飽きると思うけど、「本来1000円の価値のランチの端っこにカレー粉をかけてカレーだと言い張る」という手も使えるかもしれない。こういう状況なら、確かにmojixさんの危惧する状況が起きるかもしれない。

でも、そんな状況、ありえないでしょ。

mojixさんがこのたとえ話において「お金のない人にも、せめてカレーくらい食べさせてあげよう」というカレー無料法の趣旨、および500円という補助金の金額を設定したのは、「これぐらいの設定ならまあ無理がないだろう」という想定があったわけでしょう(もちろん実際には1食500円の補助は世論の支持は得られるわけがないんだけどまあ3000円よりはマシだ)。しかし、この設定の上では、mojixさんの「思考実験」におけるその後の展開には無理がありすぎる。

わかってやってるのなら読者をだます行為ですし(だまされる方がひどい、というレベルですが)、本人もこれを信じちゃってるのだとしたら――ちょっともう救いようがないとしか言いようがない。

参考:
「カレー無料法」の馬鹿馬鹿しさは比喩の馬鹿馬鹿しさだ - 紙屋研究所

*1:「お金のない人にも、せめてカレーくらい食べさせてあげよう」という趣旨の法律なのだから、身なりが汚いからって入店を拒否することはできないはずだ。

「憂鬱なプログラマのためのオブジェクト指向開発講座」はどうトンデモなのか

前回の続きです。

なお、私が持っているのは初版第10刷、正誤表がこちらにあるようです。

この人、Cで開発したことあるのかな

オブジェクト指向の教科書ではよくあることですが、この本も、Cによる開発とオブジェクト指向言語(この本の場合はC++)による開発を対比し、「C++の方がこんなにいいでしょ」という説明が随所にあります。そのこと自体は悪いことだとは思いません。
しかし、そういうことを書くなら、Cによるまともな開発についての知識が必要なんじゃないでしょうか。
p.30

クラスの宣言は一般的にヘッダファイルに記述します.C言語でのプログラミングでは,ヘッダファイルをプログラマが書く機会というのはあまり多くありませんでしたが,C++ではクラスを作るたびにヘッダファイルを書くことになります.

いや、本当に本当の入門者でない限り、Cプログラマだってヘッダファイルぐらい書きますってば。ていうか、経験を積んだCプログラマほど、.cファイルよりもヘッダファイルを大事にするものです*1

p.89

C++でもっとも一般的なクラスインスタンスの生成方法は,動的にヒーブ領域に取る,という方法です.つまり,Cでいえばmalloc()です.これを意外に思った人は多いのではないでしょうか.なぜならば,C言語でのプログラミングでは,malloc()でのデータ管理というのはとてもマイナーな方法だからです.しかし,C言語で今ひとつ脇役であった構造体が,C++でクラスに姿を変えて主役になったように,malloc()も姿を変えて主役になったのです.
何に姿を変えたのでしょうか.それはnewです.

この本の連載時の時代状況を考えても、Cにおいてもmalloc()はマイナーではなかったと思います。もちろん今でも状況によっては気楽には使えないかもしれませんが、そういう状況なら、C++のnewだって同じでしょう。構造体が「今ひとつ脇役」というのもどこの世界の話なんだか。

不完全型のような、Cにおける必須のテクニックも「なかったこと」にされています。
p.28

このようにクラスについてわかってくると,C言語のデータに対する考え方は実に楽観的で,構造体などはなんとも危うい仕組みだと思えてきます.FILE構造体なども,絶対に内部に触れてはいけないものなのですが,それを防ぐ仕組みがなにもなく,むき出しになっています.

FILEが無防備に公開されているのは、stdio.hが古いことと、マクロとかの都合によるもの(たぶん)であって、Cの言語仕様としては非公開にできるので『それを防ぐ仕組みがなにもなく』は間違いです*2

インベーダーの話

インベーダーについては前回も書いたのですが、4章のまとめ的なところでクラス図が登場しています。
p.83

関連や継承がないのは「まだ習ってないところ」だからです。それはさておき、

  • この「戦車」の右に移動、左に移動というメソッドは、誰が呼んでくれるんでしょうか。「インベーダー」も同様。
  • 細かいことのようですが、インベーダーミサイルや戦車ミサイルに「縦位置」だけあって横位置がないのはなぜなんでしょうか(単なる誤植?)。

クラス図といえばこの章には以下のようなクラス図もあって、
p.72

「生徒」に「平均点算出」とかのメソッドを付けてしまうのは、私は設計としておかしいと思うのですが、それはまあいいとして、「テスト」の属性に挙げられている「点数」は何でしょうか。そもそもこの「テスト」のインスタンスは、1回のテストの実施につき1個なのでしょうか。1回のテストの実施の中の、個別の生徒で1個なのでしょうか。

末尾スペース除去可能文字列クラス

p.134から、「プログラムレベルでの継承の例」として、文字列クラスを継承した「末尾スペース除去可能文字列クラス」を作っています(ある程度心得がある人なら、こう聞いただけで頭がクラクラしてくるでしょうが)。
ちょっと考えればわかることですが、末尾スペース除去の対象としたい文字列は、たとえばファイルから読むなりGUIから入力されたりしたもので、そのクラスは「文字列」です。「末尾スペース除去可能文字列クラス」を作ったって、一度生成されたインスタンスのクラスが変わることはないのですから役に立ちません*3
実は拙著「Java謎+落とし穴徹底解明」の「3.5.2 ケーススタディ――Point2Dに機能追加」という項は、執筆終盤にこの本を見て、「こんなアホウなことを考える人がいるんだ」とあわててねじ込んだ項です。
この本では、さらにその後、オーバーライドの例として、既存の文字列クラスのsetterをオーバーライドして「末尾のスペースが必ず削除される文字列」クラスも作っています*4

これはとても素晴らしいことです.なぜなら,「文字列」クラスをカスタマイズしたにもかかわらず,その文字列クラスにはまったく手を触れる必要がないのです.従来の方法では,モジュールをカスタマイズすると,今までそのモジュールを使用していた部分のテストは一からやり直しでした.そしてそのモジュールを使用している他のプログラムのソースには,旧バージョンのモジュールが生き続けることになりがちです.これは,同時に複数のバージョンのモジュールをメンテナンスするということになり,保守の面で深刻な問題になっていました.
しかしオブジェクト指向では,そのようなことを気に止めることすら時間の無駄です.
継承を使用すれば,過去のことを何も考えずにばりばりカスタマイズしてもまったく問題がありません.なぜなら,どんなに派手なカスタマイズをしても,その基底クラスのモジュールのソースは1バイトも変わっていないからです.

基底クラスのモジュールのソースは1バイトも変わっていないかもしれませんが、こんなわけのわからない文字列のインスタンスを、たとえば引数とかで渡された側はたまったものではないでしょう。もっともC++の場合、インスタンスの(ポインタでない)実体を扱えるという変わった言語なので、引数で渡される際には文字列になっており問題ないのかもしれませんが、そういうことなら、そもそもsetterをオーバーライドすること自体が役に立ちません(C++ではポリモルフィズムはポインタ経由でなければ動かないので)。
ところで、setterをオーバーライドして文字列末尾の空白を削除するというのなら、派生側のsetterは、どのようにして基底クラスが保持している文字列のメンバ変数にアクセスするのでしょうか。基底クラスがメンバ変数をpublicもしくはprotectedにしているのでない限り直接はアクセスできませんから*5、アクセスするには基底クラス側のsetterを呼ぶ必要があります。そのためには「基底クラス名::メソッド名()」とか書く必要があるのですが、この本の中には、これに関する説明はありません。これじゃわからないだろう、と思ったら、やっぱりわからない方がいらっしゃったようです。
http://www.seshop.com/book/qa/14479/thread

この場合は、派生クラス側でスペースを除去し、そこでできた文字列を、基底クラス側の「文字列設定」メソッドを呼んで基底クラスの「文字列」というデータに設定します。ただ、わかりづらいことも否めないと思いますので、今後の検討材料とさせていただきたいと思います。

だってさ。

時代の問題?

Web上のこの本の批判や、前回の記事のブックマークコメントで「この本は古いからしょうがないよね」的な意見が散見されました。確かにこの本には、「当時はみんなこんな(おかしな)こと言ってたねえ」という点もあります。「メンバ関数は必ずvirtual、publicでなくてもprotectedにしとけ」とか。
でも、上で挙げたようなことは単純に間違いであり、「古いからしょうがない」と擁護できるような性質のものではないのではないでしょうか。
ところで、「昔のオブジェクト指向では常識だった」といったことを考えるに、この業界内でのプログラミングの方法論がA→B→Cと遷移したとき、BがAよりはずいぶんマシであり、でもCはBよりずっとよい、というのなら、方法論は進化を続けているということです。Bの時点でCを思いついていた人がいなかったのはしょうがない。
でも、Bが、Aと比べても特にいいことないよね、ということなら、B時点でBを称揚した人は単に間違っていたということです。そして、そういう人が業界内にたくさんいたようなら、今あるCも、疑いの目で見る必要があるように思います。オブジェクト指向では、このあたり、どうなのでしょうか。

その他細かいこと

p.362

さて,それらを学習する前に一つ知っておかなければならないことがあります.これは「実体」です.
C言語では,関数に変数を渡すときは,値渡しとポインタ渡しの2種類の方法がありました.C++では,さらにもう一つの方法として,実体渡しという方法があります.
実体渡しは,値渡しとポインタ渡しの中間のような方法です.
まず、従来からある「値渡し」と,ここで学ぶ「実体渡し」の違いについて考えてみましょう.値渡しでは,関数に渡されるのは,あくまでもその変数の「コピー」です.ですから,渡されたデータをいくら書き換えても,元のデータには全く影響がありません.しかし、実体渡しの場合はその「変数そのもの」,つまり実体が渡ります.これを書き換えたら,元データにはもちろん影響します.それは,元データそのものなのですから.

私の知る限りにおいて、「実体渡し」という言葉をこういう意味(つまり「参照渡し」の意味)で使っている例は、この本と、この本の読書ノート的なWeb記事でしか見たことがありません。たいてい、「実体渡し」と言えば「値渡し」の方を意味するんじゃないでしょうか。
言っていることはわかります。私などは「ポインタじゃなくて実体を渡す」という意味で「実体渡し」という言葉を使ってきたわけですが*6、「コピーじゃなくて実体を渡す」という意味で「実体渡し」という言葉を使って悪いことはないでしょう(どうせきちんと定義された用語ではないので)。でも、あまり一般的な使い方とは思えません。私の周りだけかもしれませんが、Cプログラマにとって「ポインタじゃなくて実体」という言い回しはかなりされると思っていて、わざわざ混乱を招くような用語を使う意味はあるのでしょうか。この本の中でも、p.173には、集約の実装方法として

通常の関連をC++で実装する際には,メンバにそのクラスのポインタを持つことによって実装する,ということは以前学習した通りです.それに対して集約の実装は,メンバにクラスの実体を持ちます.ポインタではなく,実体なのです(LIST7-4).

という記述もあって、どう解釈したものかと思っているのですが。

また、グローバル変数について以下のような記述があって、
p.207

C言語のプログラミングにおいて,一般的に「グローバル変数は基本的に使ってはいけないもの」とされています.ほとんどの人はそれに反対はしないでしょう.
(中略)
この問題をオブジェクト指向的視点から見ると,これは「解決できない問題」というよりは,「解決しようとせずにほったらかしになっている問題」というようにしか見えないといっても過言ではありません.なぜならば,オブジェクト指向の概念に基づいてプログラミングを行うと,グローバル変数に似た構造の変数が無数に登場しますし,そしてそれを管理することが当然になっているからです.
それはなんでしょうか.(もうおわかりだと思いますが)それはクラスのデータメンバです.
なぜグローバル変数が他の変数と違って特別扱いされるかというと,それは関数が終わっても消えてなくならず,その結果,複数の関数から読み書きが可能だからだといえるでしょう.そしてこれはまさに,クラスの中でのデータメンバと同じ性質です.なぜならデータメンバは,複数のメンバ関数から読み書きされるというのが基本的な性質であり,それがメンバ関数内で宣言される通常の変数ともっとも違う点だからです.もし,グローバル変数という存在が持っているそのような性質そのものに問題があるのだったら,それはクラスの構造,さらにはオブジェクト指向という概念自体が否定されることになってしまいます.

クラスのデータメンバは、確かに複数のメンバ関数から読み書きされ、クラスが大きくなりすぎればグローバル変数的な様相を呈します。しかし、通常のデータメンバはインスタンス単位です。グローバル変数と対比すべきはstaticなデータメンバで、この本ではp.156からその説明が出てきます――が、ここではグローバル変数の話はカケラも出てきません。
どうもこの人、システムに対し1個だけ存在するのか複数存在するのかとか、多重度とか、そういったところの扱いがずいぶん無頓着に感じます。上のp.72のクラス図で、「テスト」が何に対してひとつなのかが変なことになっているのもその現れじゃないかなあ。

*1:p.255には『これはC言語の頃からの原則ですが,「関数のプロトタイプ宣言やクラスなどの宣言」は.hファイル,「その実際の実装」は.c,.cppファイルになります』という記述もあるのですが。

*2:少なくともFILE構造体は一般ユーザはポインタ経由でしか使わないので。

*3:いったんインスタンスまで作り直してしまうなら別ですが。

*4:追記:「末尾スペース除去可能文字列クラス」はどう考えても役に立ちませんが、「末尾のスペースが必ず削除される文字列」クラスのほうは、使い道がなくもない気はします。よい設計かどうかはさておき。

*5:この本でも、メンバ変数はprivateにすることを勧めています。

*6:本とかでは「値渡し」と書いてきたと思いますが