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