C,C++,VCに関する雑多なこと C,C++†出力オペレータ†vectorや自分で作ったクラスに対して画面出力オペレータを定義する. 以下はvectorに関してオペレータを作成した場合の例. //! vectorの出力オペレータ template<class T> inline ostream &operator<<(ostream &out, const vector<T> &x) { vector<T>::const_iterator i = x.begin(); for(; i != x.end(); ++i){ out << *i << " "; } return out; } Win32環境でのマルチスレッド†Win32でのスレッド生成には,
などがある.CreateThread はメモリリークがあるらしい. _beginthreadが一番簡単で,スレッドハンドルも_endthreadで閉じてくれる. _beginthreadexが一番安全なもよう.ただし,スレッドハンドルはCloseHandleで手動で閉じる必要がある. 以下は_beginthreadexを用いたもっとも単純な例 #include <process.h> #include <Windows.h> // スレッド関数 unsigned int func(void *x) { for(int i = 0; i < 10; ++i){ cout << "thread " << *((int*)(x)) << endl; } _endthreadex(0); return 0; } int main(void) { HANDLE handle; int x = 1; // スレッドを開始 handle = (HANDLE)_beginthreadex(NULL, 0, (unsigned int (__stdcall*)(void*))func, &x, 0, NULL); for(int i = 0; i < 10; ++i){ cout << "thread 0" << endl; } // スレッド終了を待つ WaitForSingleObject(handle, INFINITE); // ハンドルを閉じる CloseHandle(handle); return 0; } メンバ関数ポインタ†クラスのメンバ関数を関数ポインタを使って扱う方法. class FuncPtrTest { public: void Func1(int i){ cout << i << endl; } void Func2(int i){ cout << 2*i << endl; } }; メンバ関数ポインタ変数は, void (FuncPtrTest::*pFunc)(int) = &FuncPtrTest::Func1; のようにしてとることができる. typedefで関数を定義する場合は以下. typedef void (FuncPtrTest::*FUNC)(int); オペレータ"->*",".*"を用いた呼び出し†呼び出す場合は, FuncPtrTest *pFuncClass = new FuncPtrTest; (pFuncClass->*pFunc)(1); となる.ポインタでないクラスオブジェクトを用いる場合は以下のようになる. FuncPtrTest funcClass; (funcClass.*pFunc)(1); typedefした場合は以下. FUNC defFunc = &FuncPtrTest::Func2; (pFuncClass->*defFunc)(8); メンバ関数内から呼び出す場合はthisポインタを用いる. class FuncPtrTest { public: void Func1(int i){ cout << i << endl; } void Func2(int i){ cout << 2*i << endl; } void Test(void (FuncPtrTest::*func)(int)); }; void FuncPtrTest::Test(void (FuncPtrTest::*func)(int)) { (this->*func)(2); } void main(void) { void (FuncPtrTest::*pFunc)(int) = &FuncPtrTest::Func2; FuncPtrTest *pFuncClass = new FuncPtrTest; pFuncClass->Test(pFunc); delete pFuncClass; } テンプレートを用いた呼び出し†テンプレート関数を用いることでもクラスオブジェクトを指定することができる. template<FuncPtrTest* P> void FuncT(int i) { P->Func1(i); } FuncPtrTest g_FuncClass; void main(void) { FuncT<&g_FuncClass>(8); } ただし,テンプレートに指定するクラスオブジェクトはグローバル変数でなければならない. boost::bindを用いた呼び出し†boost::bindを用いることで,通常の関数ポインタとメンバ関数ポインタを 区別なくboost::functionとして扱うことができる. まず,boost::functionを用いて関数を定義する. #include <boost/bind.hpp> #include <boost/function.hpp> void TestBind(boost::function<void (int)> func) { func(16); } 関数の呼び出しでは,bindを用いてクラスオブジェクトを指定する. FuncPtrTest *pFuncClass = new FuncPtrTest; TestBind(boost::bind(&FuncPtrTest::Func2, boost::ref(pFuncClass), _1)); コード例†#include <boost/bind.hpp> #include <boost/function.hpp> class FuncPtrTest; typedef void (FuncPtrTest::*FUNC)(int); class FuncPtrTest { public: void Func1(int i){ cout << i << endl; } void Func2(int i){ cout << 2*i << endl; } void Test(void (FuncPtrTest::*func)(int)); }; void FuncPtrTest::Test(void (FuncPtrTest::*func)(int)) { (this->*func)(2); } template<FuncPtrTest* P> void FuncT(int i) { P->Func1(i); } void TestBind(boost::function<void (int)> func) { func(16); } FuncPtrTest g_FuncClass; void main(void) { FuncPtrTest *pFuncClass = new FuncPtrTest; void (FuncPtrTest::*pFunc)(int) = &FuncPtrTest::Func1; (pFuncClass->*pFunc)(1); pFunc = &FuncPtrTest::Func2; (pFuncClass->*pFunc)(1); pFuncClass->Test(pFunc); FuncT<&g_FuncClass>(8); FUNC defFunc = &FuncPtrTest::Func2; (pFuncClass->*defFunc)(8); TestBind(boost::bind(&FuncPtrTest::Func2, boost::ref(pFuncClass), _1)); delete pFuncClass; } 実行結果 1 2 4 8 16 32 ビット演算†
実行例 1011&0101 = 0001 1011|0101 = 1111 ~1011 = 0100 1011^0101 = 1110 1011>>2 = 0010 1011<<2 = 1100 メンバ関数テンプレート†class rxTemplateTest2 { Type data; public: rxTemplateTest2(); ~rxTemplateTest2(){}; template<typename T> void InlineFunc(Type x) { data = x; } template<typename T> void Func(Type y); }; template<typename Type> void rxTemplateTest2::Func(Type y) { data = y; cout << data << endl; } テンプレートクラス†template<class Type> class rxTemplateTest { Type data; public: rxTemplateTest(); ~rxTemplateTest(){}; void InlineFunc(Type x) { data = x; } void Func(Type y); }; template<class Type> rxTemplateTest<Type>::rxTemplateTest() { data = 0; } template<class Type> void rxTemplateTest<Type>::Func(Type y) { data = y; cout << data << endl; } Visual C++だとテンプレートクラスの実装をcppファイルに書くと テンプレートクラスを実体化できない設計になっている(inclusion-model)ので, 基本的にはヘッダにすべての実装を書くこと. どうしてもcppファイルに書きたい場合は,テンプレートクラスの実体を明示する(明示的実体化). 上記の例だと, #include "template_test.h" template<class Type> rxTemplateTest<Type>::rxTemplateTest() { data = 0; } template<class Type> void rxTemplateTest<Type>::Func(Type y) { data = y; cout << data << endl; } template class rxTemplateTest<int>; template class rxTemplateTest<float>; プリプロセッサ†コンパイル前にソースに対して行われる前処理のこと. C言語のプリプロセッサ命令(ディレクティブ)には"#"が頭に付く. #include†ヘッダファイルの読み込み #include <stdio.h> #include "vec.h" 基本的にはシステムで用意されているヘッダは<>で囲み, 自分で作成したヘッダを""で囲む. #define†マクロ置換.数値や文字列などの定数として扱える. #define 定数名 置換後の数値や文字列 例えば, #define PI 3.14159265358979323846 #define GRAVITY 9.80665 #define FILENAME "test.dat" マクロ関数として関数も定義できる. #define AREA(r) (r*r*PI) #define MAX(a, b) ((a > b) ? a : b) #define FEQ(a, b) (fabs(a-b) < 1e-8) 複数行にわたるマクロ†マクロは基本的に1行に書かなければならないが,複数行にどうしてもなってしまう場合は, #define RXFOR2(i0, i1, j0, j1) for(int i = i0; i < i1; ++i) \ for(int j = j0; j < j1; ++j) #define RXFOR3(i0, i1, j0, j1, k0, k1) for(int i = i0; i < i1; ++i) \ for(int j = j0; j < j1; ++j) \ for(int k = k0; k < k1; ++k) のように"\"を行末に付ける."\"の後には何も書かないこと(コメントも×). #undef†#defineで定義した記号定数,マクロ関数などを無効にする. #undef PI #if 〜 #else 〜 #endif†if文と同じようなもの. #if 式1 処理1 #elif 式2 処理2 #else 処理3 #endif 式には0や1などの数値を直接指定したり, defined()でマクロ定義されているかどうかの判別などを指定できる. #if defined(DEF) #endif 否定"!"も使える #if !defined(DEF) #endif 式にはC言語で使えるものはほとんど使える(==や<,<=,&&,||など) また,#ifdefを使えば,#if defined()と同じとなる #ifdef DEF #endif 否定の場合は #ifndef DEF #endif 既定義マクロ†コンパイラによって事前に定義されているマクロがいくつかある.
マクロ置き換え演算子"#","##"†
プリプロセッサによるインクルードガード†ヘッダファイルなどが複数回読み込まれるのを防ぐのに#ifndefを用いる. #ifndef _HEADER_H_ #define _HEADER_H_ ヘッダの内容 #endif // _HEADER_H_ "_HEADER_H_"はヘッダファイルごとにユニークなものを用いる. C言語からC++のヘッダを読み込む†#ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif 入出力ストリームの書式指定†C++の入出力ストリームは変数の方を気にせずに使えるので便利だが, 小数点以下の表示制度などを操作したい場合などもある. そのときに使えるのがマニピュレータ. #include <iomanip> マニピュレータの一覧は以下. (using namespace std; にしていることを前提として記述)
また,cout,cinにはメンバ関数setf(), unsetf()があり,これらによりまとめて設定できる.
引数は"|"で結合できる. そのほか,coutのメンバ関数を用いた書式指定としては,
スリープ†
時間計測†
std::string で CString::Format や printf のように文字列を入力†std::ostringstream を使用. #include <sstream> #include <string> std::ostringstream stream; stream << "step : " << i; std::string str = stream.str(); RTTI†RTTI(run-time type identification)は日本語では,実行時型情報となり,そのまんま実行時に型の情報を得る機能である. 最新のANSI C++ではサポートされているので, #include <typeinfo.h> として, int x = 10; cout << "type : " << typeid(x).name() << endl; や int x = 10; if(typeid(int) == typeid(x)){ xがint型だったときの処理 } という風に使える. このRTTIは,クラスのポリモーフィズム(多態性)を使うときに便利である. GLUTなどでDOS窓を出さない†#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") 複数モニタの検出 - Platform SDK GDI†#include <windows.h> EnumDisplayMonitors(...); GetMonitorInfo(...); など MSDN参照. |