Version 6.04
あるのにない!!
「さて今回は、使えると思ったら使えない! って話」
『どゆこと?』
「たとえば、前に紹介したこんなコード」
int i;
std::ifstream cIFStrm;
cIFStrm.open( "Data.txt" );
cIFStrm
>> i;
『ファイルから読み込むのだね』
「これは Ver 5.09 ( No.074 ) で紹介したね。たとえばこのコードが、本
に載ってるとかホームページに書いてあるとかで、そのまま書き写したとし
ます」
void CDebugDlg::OnButton1()
{
int i;
std::ifstream cIFStrm;
cIFStrm.open( "Data.txt" );
cIFStrm
>> i;
}
「これをこのままビルドするとエラーになります」
DebugDlg.cpp
error C2653: 'std' : 識別子がクラス名でも名前空間名でもありません。
error C2065: 'ifstream' : 定義されていない識別子です。
error C2146: 構文エラー : ';' が、識別子 'cIFStrm' の前に必要です。
「なんでだっけ?」
『えーっと、こういうのを使うためにはインクルードしなきゃいけないって
ことだよね。このときは確か fstream っていうのをインクルードしたね』
「そう、 std::ifstream の宣言が fstream ヘッダーファイルに書かれてる
から、これを使うためにインクルードする必要があるんです」
#include "stdafx.h"
#include <fstream> // ここ。
#include "FileTest.h"
#include "FileTestDlg.h"
「こういうことは、 iostream だけじゃなくて、ランタイムでも API でも
MFC でもあることだから」
『つまり、関数とかクラス使うためにインクルードしなきゃいけないことが
あるってこと?』
「そういうこと。基本的に MFC を使ってるときは、基本的な API 、ほとん
どの MFC 、一部のランタイムがそのまま使えるようヘッダーファイルをイ
ンクルードしてます」
『たとえば?』
「たとえば fopen() 。 MSDN で見てみて」
『 MSDN 〜』
「 MSDN の fopen() のリファレンスに〈必要なヘッダー〉ってあるでしょ」
『 stdio.h がそうだって書いてあるね。つまりこれが、インクルードしな
きゃいけないファイルなんだ。あ、でも』
「そう、 Ver 5.11 ( No.076 ) ではわざわざインクルードしてないでしょ。
これは、もともとインクルードしてるから」
『 MFC がってこと?』
「そういうこと。 MFC のインクルードファイル Afx.h でインクルードして
ます。ちなみに Afx.h は Afxwin.h でインクルードしてて、この Afxwin.h
は各プロジェクトの stdafx.h でインクルードしてます」
『なんか複雑』
「うん、実際には〈インクルードされてるかどうか〉は調べなくていいよ。
来週解説するけど、調べるのも大変だし、2重にインクルードしても問題な
いから」
『ん? つまり、わざわざ stdio.h をインクルードしても大丈夫なんだ』
「そゆこと。で、どのヘッダーファイルにあるって知ってるならインクルー
ドしておいてもいいし、しないでおいてエラーが出たら、でもいいし」
『 std::ifstream が fstream にあるって調べるのはどうすればいい?』
「まずは MSDN 。ランタイムはさっき言った〈必要なヘッダー〉に書いてあ
るから。 MFC の場合は…… CWnd を見てみて」
『ほい。あ、下のとこに #include <afxwin.h> ってあるね』
「そう、これをインクルードすれば OK 」
『そういえばこれは stdafx.h でインクルードしてたんだ』
「 API の場合は…… GetWindowText() の API のを見てみて」
『日本語のと英語のがあるけど』
「両方とも。日本語の方は〈ヘッダ : winuser.h 内で宣言〉って書いてあ
るし、英語の方は "Header: Declared in winuser.h." って書いてあるし」
『これ見てインクルードすればいいんだね』
「それか【ファイルから検索】でどこにあるか調べるか。ただ、 MFC やラ
ンタイムは、ソースファイルでも引っかかるから気を付けて」
『……ソースファイルはインクルードしちゃいけない?』
「いけません。ヘッダーファイルには関数やクラスを使うために必要な情報
が、ソースファイルには関数やクラスが機能するための中身が入ってます。
使うのに必要なのは」
『ヘッダーファイル、ってことね』
「ま、拡張子で見分ければソースファイルかどうかはわかるでしょ」
『それに、置いてあるフォルダ違うし』
「あ、そっか。僕は【サブフォルダも探す】で API も MFC もランタイム
も、ヘッダーファイルもソースファイルも全部いっぺんに検索しちゃうか
ら」
『その方がめんどそう……』
「あ、あと、 ifstream なんかの iostream 系は、 MSDN で調べると難しい
と思うよ。 std::ifstream は、ホントは std::basic_ifstream って名前だ
から」
『ホントはって? あ、 typedef !』
「そう、そういう別名になってるし、テンプレートって難しい機能も使われ
てるし。それに…… fstream って、一応ヘッダーファイルなんだけど」
『拡張子ないね』
「実は【ファイルから検索】だとこの拡張子ないのはうまくいかないんだよ
ね」
『ホントだ、【ファイルから検索】に、検索するファイルの拡張子を選ぶの
があるんだね』
「他の開発環境だと、 fstream.h が本体で、 fstream からインクルードし
てる仕組みになってるんだけどね」
『それって VC がダメってこと?』
「そういうことになるのかなぁ……ま、こういうふうに iostream の場合に
は難しい部分があるけど、基本は MSDN か【ファイルから検索】で」
『ほいほい』
「で、ここまでが基本。ここからは応用」
『……難しい?』
「ちょっとね。まず、さっきの std::ifstream の例で、コンパイルエラー
が出ないようにしましょう。 fstream をインクルードして」
『この前と同じようにすればいいんだよね。じゃ、ここ』
#include "stdafx.h"
#include <fstream> // ここ。
#include "Debug.h"
#include "DebugDlg.h"
「ビルドっ、エラー出ません!」
『さて今度は、 std::ifstream を CDebugDlg のメンバ変数として持たせて
みましょう。 DebugDlg.h を開いて』
class CDebugDlg : public CDialog
{
std::ifstream m_cIFStrm; // ここに追加。
// あとは略。
『ビルド、うおエラーが出た!』
Debug.cpp
error C2653: 'std' : 識別子がクラス名でも名前空間名でもありません。
error C2146: 構文エラー : ';' が、識別子 'm_cIFStrm' の前に必要です。
error C2501: 'ifstream':識別名を宣言するのに、型が指定されていません
『あれ? このエラーって、さっきの fstream をインクルードしてなかっ
た時に出たのと似てない?』
「ほとんど同じ。つまり、 std::ifstream なんてどこにもない! って言
われてるわけ」
『ええっ!? それ変!! ちゃんとインクルードしたもん』
「うん、 DebugDlg.cpp でインクルードしたはずだよね。ちょっとコンパイ
ルの話思い出してみて。コンパイルって、各ソースファイルごとにするって
言ったでしょ」
『うん、言った』
「ってことは、ヘッダーファイルの読み込みも、各ソースファイルごとにさ
れてなきゃいけないってこと。上のエラーよく見て。 Debug.cpp って書い
てあるでしょ」
『ホントだ! さっきのエラーは DebugDlg.cpp って書いてあったのに』
「さっきのエラーは DebugDlg.cpp をコンパイルしてたときに出たエラー、
今度のは Debug.cpp をコンパイルしてたときに出たエラー。 Debug.cpp の
インクルードしてる部分を見ると……」
#include "stdafx.h"
#include "Debug.h"
#include "DebugDlg.h"
「ここで DebugDlg.h をインクルードしてるでしょ」
『そっか! ここでも fstream をインクルードしないと、 DebugDlg.h の
中で std::ifstream 見つけても何か分かんないんだ!』
「そういうこと。このままだと、 Debug.cpp をコンパイルしてるときに
std::ifstream の情報が全然入ってないから、 DebugDlg.h を読み込んだと
きに std::ifstream を理解できないわけ」
『はー、なるほど。ってことは』
#include "stdafx.h"
#include <fstream>
#include "Debug.h"
#include "DebugDlg.h"
『ってすればいいんだ。あ、質問! インクルードって、上から順番にして
く?』
「してくよ。だからその順番」
『なのね。だから』
#include "stdafx.h"
#include "Debug.h"
#include "DebugDlg.h"
#include <fstream>
『ビルド。あ、やっぱり同じエラーが出た。 Debugdlg.h をインクルードす
る前に fstream をインクルードしなきゃいけないわけね』
「そう、情報が先に入ってないと。あと、こういうふうに各ソースファイル
でインクルードするのは面倒だから、たいがいは stdafx.h の中でインク
ルードします」
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <fstream> // ここ。
『そっか、 stdafx.h って Debug.cpp からも DebugDlg.cpp からも インク
ルードされてるから』
「そういうこと。 <> で囲むようなの、つまりライブラリのヘッダーファイ
ルをインクルードするときには stdafx.h でした方がいいかな」
『そういえば、 <> で囲むのと "" の違いは?』
「 "" はプロジェクト内のファイル。 <> は、【ツール】−【オプション】
ダイアログの【ディレクトリ】−【インクルードファイル】見てみて」
『あ、さっき言ってた API や MFC の置いてあるフォルダ!』
「ここに指定してあるフォルダからインクルードファイルを探すのが、 <>
でのインクルード」
『ってことは、これで好きな所にインクルードファイル置けるの?』
「もちろん。他の人が作ったライブラリを使う時には、そのライブラリの置
き場所をここで指定するようにね」
『 API とかのフォルダにコピーしちゃダメ?』
「駄目!!」
/*
Preview Next Story!
*/
『そういうのダメなの?』
「ダメだって」
『なんで?』
「元々あるのと同じ名前のファイルがあったらまずいでしょうが」
『う”、そういえば』
「というわけで次回」
< Version 6.05 プリプロセッサとマクロ >
『につづく!』
「力業に頼らず、スマートに! これが優れたプログラマーへの近道」
『こんなだらだら教えてる人が何言ってんだか』
「はぅ」