C++ memo
2008年1月30日
Suns & Moon Laboratory
はじめに
C++の勉強中です
C言語も勉強中です。
typedef
参考:typedef enumの使い方を教えてくださいNo.3
enumについては5種類の書き方があり、
1) enum E { e1, e2 };
2) enum E { e1, e2 } v;
3) enum { e1, e2 } v;
4) typedef enum E { e1, e2 } Ea;
5) typedef enum { e1, e2 } Ea;
というものです。
(1)は標準的な"型定義のみの"記法です。
(2)は(1)の効果に加えて、変数宣言も同時に行うものです。このときvの型はEです。
(3)は変数宣言を行う記法です。このときはvの型は"無名"になり、プログラム中でvの型を記述することはできません。
(4)は型定義と型の別名宣言を同時に行う書式です。Eの別名Eaを宣言しています。これはenum Eと書かずにE2に書けるようにするためで、単に記述がしやすくなることを狙ったものです。
(5)は(4)から型の名前を除いたものです。enumのオリジナルの型は無名になってしまいますが、(3)と違い、E2として型名を参照できるので、プログラム中で無名型をE2として再利用することが出来ます。
typedef enum
typedef enum
{
	ROTARY_SEQ_IDLE,
	ROTARY_SEQ_CHG,
	ROTARY_SEQ_DOWN,
} ROTARY_SEQ_STATE;
typedef struct
typedef struct struct_pattern{
	unsigned short PatternStart;
	unsigned short PatternEnd;
}PATTERN_t;
CとC++の混在時名前解決
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
最大値
limits.hに定義されている。
coutを手っ取り早く使う
#include <iostream>
using namespace std;
void sample()
{
  cout << "Hello" << endl;
}
継承
class IxTest{
  private:
  protected:
  public:
    virtual void Init(); //IxTestで実装、継承して実装可能。
    virtual void Test() = 0; //純粋仮想関数。IxTestでは実装しない。この場合IxTestクラスはインスタンス化できない。
};
class IxTestCustom : public IxTest{
  public Test();//純粋仮想関数を実装したので、IxTestCustomはインスタンス化出来る
};
抽象クラス (C++)
インターフェース
インターフェース実装の例。わかりやすい。
一週間で身につくC++言語の基本 - 第6日目:virtualと仮想関数
テンプレートを使った関数
 template <class T> double GET_PIXELS(IkImage &Image,const int sx,const int sy,const int w,const int h){
 	double result = 0;
 	int line_bytes = Image.get_line_bytes(Image.Width(),Image.BitsPerPixel());
 	for(int y=sy;y<(sy+h);y++){
 		T *ptr;
 		ptr = (T *)(Image.PixelData + (sx * sizeof(T)) + (line_bytes * y));
 		for(int xc=0;xc<w;xc++){
 			result += *ptr;
 			ptr++;
 		}
 	}
 	return result / (w * h);
 }
 void IkImageManiGetPixels::Execute(IkImage &Image,const int sx,const int sy,const int w,const int h)
 {
 	if(Image.BitsPerPixel() == 8){
 		Color = GET_PIXELS<BYTE>(Image,sx,sy,w,h);
 	}else if(Image.BitsPerPixel() == 16){
 		Color = GET_PIXELS<WORD>(Image,sx,sy,w,h);
 	}else{
 		throw "Error! not supported pixel format";
 	}
 }
無名の名前空間
参考:msdn→Deep C++ 無名の名前空間
文字列と戻り値
参考:どう書く?C++
例外
#include <iostream>
using namespace std;
void func1(void)
{
	cout << "func1 start" << endl;
	try{
		throw "throw func1\n";
	}
	catch(...){
		cout << "func1 catch" << endl;
		throw;//ここで例外を再生成すれば、mainでも例外を受け取れる。
	}
	cout << "func1 end" << endl;//例外再生成すると、ここにはこない
}
void main(int argc,char *argv[])
{
	try{
		cout << "main start" << endl;
		func1();
		cout << "main called func1" << endl;//例外によってここには来ない
	}
	catch(...){
		cout << "main catch" << endl;
	}
	cout << "main end" << endl;//catchした後に、ここは実行される
}
string
文字列の追加はappend()か+=を使う。
string::erase
	src = "0123456789";
	src.erase(0,3);
	cout << "erase(0,3) " << src << endl;//No.0から3個削除 -> 3456789
	src = "0123456789";
	src.erase(1,3);
	cout << "erase(1,3) " << src << endl;//No.1から3個削除 -> 0456789
	src = "0123456789";
	src.erase(2,5);
	cout << "erase(2,5) " << src << endl;//No.2から5個削除 -> 01789
	src = "0123456789";
	src.erase(3);
	cout << "erase(3) " << src << endl;//No.3以降を削除 -> 012
std::queue
push()
pop()
empty()
front()
#include <queue>
std::queue<bool> queue_press;
vector
バッファとしての使用
結論を先に言うと、メモリ上の配置が連続する事は、仕様で規定されている...そうです。
ネットでそういう裏付けをさがしていたのですが、見つからなくて困っていました。
その疑問の答えが下記リンクにあります。(教えてくれてありがとう>某氏)
参考:テンポラリ・バッファとしての std::vector の利用
基本
insertよりもpush_backを使う。insertはメモリーの再確保を行うので遅い
#include <vector>
#include <iostream>
int main()
{
	using namespace std;
	vector<int> arr;
	// 要素追加
	for(int i = 0; i < 10; ++i )
		arr.push_back( i );
	cout << "配列の添え字でアクセス" << endl;
	for(unsigned int i = 0; i < arr.size(); ++i )
		cout << arr[i] << endl;
	cout << "イテレータでアクセス" << endl;
	for(vector<int>::iterator it = arr.begin();it != arr.end();it++)
		cout << *it << endl;
	return 0;
}
イテレータで移動
vector<double> v;
v.resize(10);
vector<double>::iterator it = v.begin();
advance(v,5);
コンテナの初期化
fill(),fill_n()を使う。
vector<double> v;
v.resize(100);
fill(v.begin(),v.end(),0);//すべて0にする
map
#include <map>
#include <string>
using namespace std;
	map<string,string> data;
	data.insert(map<string,string>::value_type("square","enix"));
	data.insert(map<string,string>::value_type("bandai","namco"));
	data.insert(map<string,string>::value_type("sega","summy"));
	//要素数
	cout << "要素数 = " << (unsigned int)data.size() << endl;
	//全要素出力
	map<string,string>::const_iterator it = data.begin();
	while(it != data.end()){
		cout << "key=" << it->first << " val=" << it->second << endl;
		it++;
	}
	//keyで検索
	{
	map<string,string>::const_iterator it = data.find("square");
	if (it != data.end()){//成功失敗はendと比較
		cout << it->second.c_str() << endl;
	}
	}
	//全て削除
	data.clear();
	//空?
	if(data.empty()){
		cout << "空です。" << endl;
	}
出力はこう
要素数 = 3
key=bandai val=namco
key=sega val=summy
key=square val=enix
enix
空です。
ifstream
#include <iostream>
#include <fstream>
int main(int argc,char *argv[])
{
	using namespace std;
	ifstream ifs(argv[1],ios::in | ios::binary);
	while(!ifs.eof()){
		char buf[256];
		ifs.getline(buf,sizeof(buf),'\n');
		cout << "> " << buf << endl;
	}
	return 0;
}
seekg
seekg(移動量,std::ios::beg);
静的データメンバ(静的クラスメンバ)
データメンバを静的(static)宣言すると、生成されたオブジェクトで共有するデータメンバが出来る。
で、実体は宣言されないので、別途実体を宣言すると。
class SampleClass{
 static int device_counter;
}
int SampleClass::device_counter;
参考 静的データメンバ
printf書式
longを出したいときは、l付けるの忘れない。
sprintf(buf,"%08lX",val);
関数ポインタとtypedef
typedef void (*UART_SETUP)(void);
UART_SETUP uart_setup;
void uart_a0_setup(void)
{
...
}
uart_setup = uart_a0_setup; //初期化
uart_setup(); //呼び出し
関数ポインタと構造体の初期化
よく忘れるのでメモ。
void cmd_ver(void){
  //処理
}
typedef struct{
	const char *name;
	void (*function)(void);
} name_func_st;
const name_func_st name_func_list[]={
 {"VER"		,cmd_ver	}
,{"CTL"		,cmd_ctl	}
};
関数ポインタ配列例
typedef struct
{
	const char *name;
	void (*function)(void);
} name_func_st;
const name_func_st name_func_list[] =
{
{ "KEY", sterm_cmd_key },
{ "VER", sterm_cmd_ver },
{ "HELP", sterm_cmd_help },
{ "H", sterm_cmd_help },
{ "?", sterm_cmd_help },
{ 0, 0 } };
	int index = 0;
	while (name_func_list[index].function != 0)
	{
		if (strcmp(name_func_list[index].name, params[0]) == 0)
		{
			name_func_list[index].function();
			return;
		}
		index++;
	}
クラスメンバ関数の配列呼び出し
クラス内での関数ポインタの配列を作る
https://rarara.org/community/postid/41475/
Blueさんの投稿
class Foo
{
	public:
		int func(int n, int m)
		{
			static int (Foo::*f[2])(int) = { funcA, funcB };
			return (this->*f[n])(m);
		}
	int funcA(int){return 1;}
	int funcB(int){return 2;}
};
int main()
{
	Foo foo;
	int n = foo.func(0, 0); // n = 1
	return 0;
}
文字列ポインタの配列
#include <stdio.h>
int main()
{
    const char* onof_text[] = { "On","Off" };
    char** texts;
    texts = (char**)&onof_text[0];//どっちでも一緒
    texts = (char**)onof_text;//どっちでも一緒
    printf("%s\r\n", texts[0]);
    printf("%s\r\n", texts[1]);
}
文字列の二次元配列
static const char* str_arr[3][4] = {
	{"A1","A2","A3","A4"}
	,{"B1","B2","B3","B4"}
	,{"L1","C2","C3","C4"}
};
	char* ptr = (char*)str_arr[alpha_index][num_index];
デフォルト引数
引数省略
void func(int a,int b=5){return a+b;}
カンマ演算子
カンマで複数の式を1つの式にまとめる事が出来る。
評価結果は右端の式の結果。
下記の場合は、2が返ってくる。
 return 1,2;
expressionとstatement カンマ演算子
ワーニング対策
未使用の引数
void ttvm_dbgout(char* /*str*/=0)
参考
●C++編(標準ライブラリ) トップページ
書籍:C++ Coding Standards
2024-08-14 11:00:22 32400