C++ ⇒ VBA 書いて覚えるための初心者自己中記事

C++ ⇒ VBA 勉強の履歴を付けるというかノート代わりに使ってます

C++ streamクラスについて 書いて覚えるための初心者自己中記事

今まで使用していた iostream やら fstream やらはクラスの継承によって派生しているものらしい。

 

stream とは入出力に関してのクラスで、基底クラスでは

istream  <-inpot用

ostream <-output用

 

が存在する。

そこからの派生クラスとして

iostream <- inpou & output用

があるらしい。

二つのクラスを継承するとかもあるんだなぁ。

 

さらにそのiostreamから派生したのが

fstream <- ファイル関係

stringstream <- 文字列関係

なんだとか。

ちなみにそれとは別に大元の

 

isreamからiftream / istrungstream

ostreamからofstream / ostringstream

があるけど

iostreamから派生したfstream / stringstream とは継承関係はない。

 

ややこしい。

 

    [              istream               ]     [                 ostream                ]

        ↑              ↑                ↑   ↑              ↑                        ↑

       [ ifstream ] [ istringstream ] [ iostream ]  [ ofstream ] [ ostringstream ]

                                                                    ↑  ↑

                     [ fstream ]   [ stringstream ]

 

こんな感じ?

 アップキャスト可能か不可能かをこれで判断するらしい。

ostream& を引数に取る関数を用意した場合、

ostream

iostream

ofstream

ostringstream

fstream

stringstream

からのオブジェクトを渡せるということ。

なんか超絶めんどくさそうな予感・・・。

 

用語

データを一旦貯めておく領域を バッファ( buffer )

データを一旦貯めておく行為を バッファリング ( buffering )

バッファリングしたデータをファイルに出力する フラッシュ ( flush )

 

ostreamクラスのオブジェクトで

標準出力

標準エラー出力

のオブジェクトがある。

 

標準出力には cout

標準エラー出力には cerr / clog

 

標準出力も標準エラー出力もデフォルトでは画面への出力。同じ。

しかし、これらは出力先を変更することができる。 ( redirect )

 

これまで使ってきた、cout , cin , fstream , stringstream , read , write , getline , << , >> 

, fail , eof , clear などstream に関わっていたものは継承で共通化されている。

 

そのため、cin で間違った入力をしてしまったりすると fail がtrue 状態。

 clear するまで入力無効!!

とかなるらしい。

 ~~~~~~~~~~

 

数時間経過

 

~~~~~~~~~~

 

windowsノートが届いたからxcodeからvisual studioにチェンジしてみようと思ったら凄い大変。(使うのほぼ初めて)

xcodeが分かりやす過ぎてvisual studioがわかりにく過ぎる・・・。

visual studio 2017 communityをインストールするときに何を入れますか?的なのがもうしんどい。

C++の勉強がしたいんですけど、逆になにをいれたら出来るんですか?って感じ。

まじ素人にやさしくない。

んで何かいろいろ検索したら win32コンソールアプリケーションなるものが目的のものらしいと分かったけど、新規プロジェクトでそれがない!!

検索しても誰かのスクショでちゃんと有る!!

意味が分からない。

何回かアンインストールして再度インストールしてみても意味なし。

仕方ないので「空のなんちゃら」ってやつを選択したらそれっぽい感じで、もうこれでいいんじゃね?ってかんじ。

 

これからはvisual studioでがんばるぞい!!

 

 

 

 

再開

 

bool SkipOnError(istream& istr) {
	if (istr.fail()){
		if (istr.eof()) {
			exit(EXIT_FAILURE);
		}
		char ch; //ここの変数が
		istr.clear();
		istr >> ch; //ここで何してるのかわからない
		return true;
	}
	else {
		return false;
	}
}
 
void main() {
	int n;
	do {
		cin >> n;
	} while (SkipOnError(cin)); // cin を引数にしてるのもわからない
	cout << "入力された値は" << n << "です。" << endl;
	system("pause");
}

 うわぁ・・・・

xcodeはただのコピペで綺麗に貼れたのに。

仕方がない。徐々によくなっていくだろう。

というか慣れたらこっちのが良いかもね。

 

今回は int 型変数 n に対して cin で入力を行って、型に入らない入力の時はやり直させる感じです。

 

コードに赤字で書いたのが理解できない点。

cin を引数にするってなに?

そういえば前にチラッと cin は istreamクラスのオブジェクトってテキストに書いてあるのみたな。

オブジェクトっていうとあれか? istream cin;  みたいな感じなのか?

cin >> n;  で入力された値を n に入れてるわけだけど cin にも入ってるって事かな?

 

ちょっとこの辺の説明がなくて分からない。

 cin を引数にするのは漠然と飲み込めるけど、SkipOnError関数内で行われているchar型変数の動きが全く分からない。

一旦、

char ch;

istr >> ch;

コメントアウトしてみたら数値以外を入力したときに次の入力が出来ない状態になった。これはヒントになる・・。

 

だめだ。わからない。

とりあえず保留だぁ。。。

 

で、ストリームの流れを操作することが出来るものがあって、これをマニピュレーター(manipulator)という。

 

テキストままでいくと、

cout << マニピュレーター;

cin >> マニピュレーター;

 

と使う。

 

print("%02X" , buf [ w ] );

とやっていたことがマニピュレーターを使って出来る。

cout << setw(2) << setfill( '0' ) << hex << uppercase << (int) buf [ w ]  << '   ' ;

 

らしい。

setw (2)   は最小幅

setfill ( '0' ) は最小幅に達しない場合に埋めるものの指定

hex  は16進数を指定するという意味

uppercase  は大文字でという意味

 

これらはcout に与えられた効果みたいな感じ。バフかな?

ただし効果時間がほとんど永続。

setw (2) のみが一度きり。他は永続。

 なのでループの中で使いたい場合はsetw 以外はループの外にしたほうがいい。

 

この永続効果のマニピュレーター、cout を他の使い方で使用したい場合はどうするのか。

 

マニピュレーター使用する前の設定を保存しておいて、使用終了したら保存していた設定を使って元に戻す。

 

 

void main() {
	ios::fmtflags flags = cout.flags();   //設定保存
	char fill = cout.fill();  //設定保存
 
	//cout に マニピュレーターを使う処理 省略
 
	cout << setiosflags(flags) << setfill(fill);  //設定復元
}

 

設定を保存する際、setfill だけは別で保存。(めんどくさい・・)

設定を保存しておくための型は ios::fmtflags という型

現在の設定を呼び出すメンバ関数は flags();

setfill() は、何か普通に char 型の変数に保存。setfill() の情報を取り出すのはメンバ関数 fill();

 

そして復元するには

setiosflags( ios::fmtflags ) ;

fill はそのまんま普通に setfill( );

 

現在の設定を呼び出すメンバ関数 flags( ); の引数に、先ほど保存した ios::fmtflags 型のオブジェクトをいれても設定できるらしい。

fill(); も同様。 

 

 

void main() {
	ios::fmtflags flags = cout.flags();   //設定保存
	char fill = cout.fill();  //設定保存
 
	//cout に マニピュレーターを使う処理 省略
 
	cout.flags(flags);  //設定復元
	cout.fill(fill);  //設定復元
}

 こんな感じ。

 あと、マニピュレーターをつかうには #inclide <iomanip> が必要。

 

 

 少しでも慣れるためにマニピュレーターを書いた

	  cin >> setw(width); //文字列入力の最大幅
	cout << setw(width); //出力の最小値
	cout << setfill(fill); //最小値に足りない部分をfillが埋める
	cout << setprecision(prec); // 少数の表示に関して、最高小数点以下prec桁まで表示
	  cin >> setiosflags(flags); // flags にまとめて設定
	cout << setiosflags(flags); // 同上
	  cin >> resetiosflags(flags); //flags で指定した設定をクリアする
	cout << resetiosflags(flags); // 同上
	  cin >> setbase(base); // 基数を base に設定する(8,10,16のいずれか)
	cout << setbase(base); //同上
	cout << boolalpha; //bool値を出力する際に true / false で出力する
	cout << noboolalpha; // 上の設定の解除
	cout << showbase; // 16進数と8進数でそれぞれ頭に 0x  0  をつける
	cout << noshowbase; // 上の設定の解除
	cout << showpoint; // 強制的に小数点を出力する
	cout << noshowpoint; // 上の設定の解除
	cout << showpos; // 正符号(+)を出力する
	cout << noshowpos; // 上の設定の解除
	cout << skipws; // 半角空白を無視
	cout << noskipws; // 上の設定を解除
	cout << uppercase; // 16進数のA~Fを大文字にする
	cout << nouppercase; // 上の設定を解除
	cout << unitbuf; // バッファリングを無効
	cout << nounitbuf; // 上の設定を解除
	  cin >> dec; // 10進数で入力
	cout << dec;// 10進数で出力
	  cin >> hex; // 16進数で入力
	cout << hex; // 16進数で出力
	  cin >> oct; // 8進数で入力
	cout << oct; // 8進数で出力
	cout << fixed; // 少数を必ず指数表記を使わずに出力する
	cout << scientific; // 少数を必ず指数表記で出力する
	cout << left; // 左詰めで出力
	cout << right; // 右詰めで出力
	cout << internal; // 符号は左に、その他は右詰めで出力
	  cin >> ws; // noskipwsを使用中なら有効。空白文字(タブ・改行を含む)を飛ばす。
	cout << endl; // 改行を出力してフラッシュする
	cout << flush; // フラッシュする
	cout << ends; // ヌル文字を出力する

 

 

 さらに、マニピュレーターを使う際の便利なやり方。

引数と戻り値にistream& や ostream& を使った関数を作ると、その関数名がマニピュレーターとなるらしい。

 

 

ostream& TestManip(ostream& testmanip) { // ostream& を引数と戻り値とした関数
	return testmanip << setfill('0') << hex << uppercase; //設定だけする
}
 
cout << TestManip; //纏めて適用出来る

 

 これは参照を返す関数になっている。

参照を返す関数についてはまたあとでやるらしい。

 

今回はここまで。