【C++】インライン関数
インライン関数の特徴
- メリット
- 関数の呼び出しと終了時に伴うオーバーヘッドが発生しないことから、通常の関数よりも早く実行できる。
- デメリット
- ファイルサイズが大きくなる。
- ループ、goto、switchを含めることができない
- 再帰してはいけない
- 関数定義の前にinlineと記述するだけでインライン関数となる。
- 関数の規模が大きい時など、コンパイラが要求を実行できない場合は通常の関数としてコンパイルされる。
- インライン関数もオーバーロードすることができる
#include <iostream> using namespace std; inline int even( int x ) { return !(x%2); } int main() { if( even(10) ) cout << "10は偶数です\n"; if( even(11) ) cout << "11は偶数です\n"; return 0; }
$ g++ -o study67 study67.cpp $ ./study67 10は偶数です
自動インライン化
#include <iostream> using namespace std; class samp { int i, j; public: samp( int a, int b ) { i = a; j = b; } int divisible() { return (i/j); } }; int main() { samp sp( 20, 5 ); cout << sp.divisible() << endl; }
$ g++ -o study72 study72.cpp $ ./study72 4
- ただし、入出力演算子はそもそも遅いので恩恵はあまり得られない
- 短くなるため、恩恵がない場合でもクラスの中に書くことは多い
引用・参考はこちら
【C++】継承②
study54.cpp
#include <iostream> #include <cstring> using namespace std; enum yn { no, yes }; enum color { red, yellow, green, orange }; void out( enum yn x ); char *c[] = { "赤", "黄", "緑", "オレンジ" }; class fruit { public: enum yn annual; enum yn perennial; enum yn tree; enum yn tropical; enum color clr; char name[40]; }; class Apple : public fruit { enum yn cooking; enum yn crunchy; enum yn eating; public: void seta( char *n, enum color c, enum yn ck, enum yn crchy, enum yn e ); void show(); }; class Orange : public fruit { enum yn juice; enum yn sour; enum yn eating; public: void seto( char *n, enum color c, enum yn j, enum yn sr, enum yn e ); void show(); }; void Apple::seta( char *n, enum color c, enum yn ck, enum yn crchy, enum yn e ) { strcpy( name, n ); annual = no; perennial = yes; tree = yes; tropical = no; clr = c; cooking = ck; crunchy = crchy; eating = e; } void Orange::seto( char *n, enum color c, enum yn j, enum yn sr, enum yn e ) { strcpy( name, n ); annual = no; perennial = yes; tree = yes; tropical = yes; clr = c; juice = j; sour = sr; eating = e; } void Apple::show() { cout << name << "りんご:\n"; cout << "一年生植物:"; out( annual ); cout << "多年生植物:"; out( perennial ); cout << "木:"; out( tree ); cout << "熱帯性:"; out( tropical ); cout << "色:" << c[clr] << "\n"; cout << "料理用"; out( cooking ); cout << "かたい"; out( crunchy ); cout << "食用"; out( eating ); cout << "\n"; } void Orange::show() { cout << name << "オレンジ:\n"; cout << "一年生植物:"; out( annual ); cout << "多年生植物:"; out( perennial ); cout << "木:"; out( tree ); cout << "熱帯性:"; out( tropical ); cout << "色" << c[clr] << "\n"; cout << "ジュース用:"; out( juice ); cout << "酸っぱい:"; out( sour ); cout << "食用:"; out( eating ); cout << "\n"; } void out( enum yn x ) { if ( x == no ) cout << "no\n"; else cout << "yes\n"; } int main() { Apple a1, a2; Orange o1, o2; a1.seta("レッドデリシャス", red, no, yes, yes ); a2.seta("ジョナサン", red, yes, no, yes ); o1.seto("ネーブル", orange, no, no, yes ); o2.seto("バレンシア", orange, yes, yes, no); a1.show(); a2.show(); o1.show(); o2.show(); return 0; }
コンパイル
$ g++ -o study54 study54.cpp
実行
レッドデリシャスりんご: 一年生植物:no 多年生植物:yes 木:yes 熱帯性:no 色:赤 料理用no かたいyes 食用yes ジョナサンりんご: 一年生植物:no 多年生植物:yes 木:yes 熱帯性:no 色:赤 料理用yes かたいno 食用yes ネーブルオレンジ: 一年生植物:no 多年生植物:yes 木:yes 熱帯性:yes 色オレンジ ジュース用:no 酸っぱい:no 食用:yes バレンシアオレンジ: 一年生植物:no 多年生植物:yes 木:yes 熱帯性:yes 色オレンジ ジュース用:yes 酸っぱい:yes 食用:no
【C++】継承①
- 継承をすることで、最も汎用的なクラスから、最も特化されたクラスへの流れを示すクラス階層を作成できる。
- あるクラスを別のクラスが継承するとき
- 継承される側のクラスを 基本クラス と呼ぶ
- 継承する側のクラスを 派生クラス と呼ぶ
#include <iostream> using namespace std; class B { int i; public: void set_i( int ); int get_i(); }; class D : public B { int j; public: void set_j( int ); int mul(); }; void B::set_i( int n ) { i = n; } int B::get_i() { return i; } void D::set_j( int n ) { j = n; } int D::mul() { return j * get_i(); } int main() { D ob; ob.set_i( 10 ); ob.set_j( 4 ); cout << ob.mul() << endl; return 0; }
- mul()に注目
- 特にオブジェクトにリンクすることなく、Bクラスのメンバであるget_i()を呼び出している。
- mul()では非公開メンバのiにアクセスできないため、get_i()関数を呼び出す。
コンパイル
$ g++ -o study52 study52.cpp
実行
$ ./study52 40
引用・参考はこちら
【C++】仮引数を受け取るコンストラクタ
- コンストラクタ関数には引数を渡すことができる
study48.cpp
#include <iostream> #include <cstring> #include <cstdlib> using namespace std; class strtype { char *p; int len; public: strtype( char * ); ~strtype(); void show(); }; strtype::strtype( char *ptr ) { len = strlen( ptr ); p = ( char *) malloc( len + 1 ); if ( !p ) { cout << "メモリ割り当てエラー" << endl; exit(1); } strcpy( p, ptr ); } strtype::~strtype() { cout << "pを開放する" << endl; free( p ); } void strtype::show() { cout << p << " - 長さ:" << len << endl; } int main() { strtype s1("This is a test."), s2("I like C++."); s1.show(); s2.show(); return 0; }
コンパイル
$ g++ -o study48 study48.cpp
実行
$ ./study48 This is a test. - 長さ:15 I like C++. - 長さ:11 pを開放する pを開放する
引用・参考はこちら
【C++】コンストラクタ関数とデストラクタ関数
study41.cpp
#include <iostream> #include <cstring> #include <cstdlib> using namespace std; #define SIZE 255 class strtype { char *p; int len; public: strtype(); ~strtype(); void set( char * ); void show(); }; strtype::strtype() { p = ( char * ) malloc(SIZE); if ( !p ) { cout << "メモリ割り当てエラー" << endl; exit(1); } *p = '\0'; len = 0; } strtype::~strtype() { cout << "pを開放する" << endl; free(p); } void strtype::set( char *ptr ) { if ( strlen( ptr ) >= SIZE ) { cout << "文字列が大きすぎる" << endl; return; } strcpy( p, ptr ); len = strlen( p ); } void strtype::show() { cout << p << " - 長さ:" << len << endl; } int main() { strtype s1, s2; s1.set( "This is a test." ); s2.set( "I like C++." ); s1.show(); s2.show(); return 0; }
コンパイル
$ g++ -o study41 study41.cpp
Warningがでますが、今回は気にしないということで。
実行
$ ./study41 This is a test. - 長さ:15 I like C++. - 長さ:11 pを開放する pを開放する
引用・参考はこちら
【C++】オーバーロード
- 関数オーバーロードの主な用途として、コンパイル時ポリフォーリズムを行うことが挙げられる
- 1つの名前をオーバーロードすることで、複数あるデータの方の種類などに対応できる
- 関数をたくさん作り、それぞれ別の名前をつける必要がない
study29.cpp
#include <iostream> using namespace std; int myabs( int ); long myabs( long ); double myabs( double ); int main() { cout << "-10の絶対値:" << myabs(-10) << endl << endl; cout << "-10Lの絶対値:" << myabs(-10L) << endl << endl; cout << "-10.01の絶対値:" << myabs(-10.01) << endl << endl; } int myabs( int n ) { cout << "整数用のmyabs()" << endl; return n<0 ? -n : n; } long myabs( long n ) { cout << "長整数用のmyabs()" << endl; return n<0 ? -n : n; } double myabs( double n ) { cout << "倍精度浮動小数点数用のmyabs()" << endl; return n<0 ? -n : n; }
コンパイル
g++ -o study29 study29.cpp
実行
$ ./study29 整数用のmyabs() -10の絶対値:10 長整数用のmyabs() -10Lの絶対値:10 倍精度浮動小数点数用のmyabs() -10.01の絶対値:10.01
引用・参考はこちら
【C++】クラスの作成
概要
- 1つのクラスに対して複数のオブジェクトを作ることができる。
- 今回はstackクラスに対して、s1とs2という名前でオブジェクトを作成する。
- オブジェクト同士は干渉しない
study21.cpp
#include <iostream> using namespace std; #define SIZE 10 // 文字列の保存 class stack { char stck[SIZE]; int tos; public: void init(); void push( char ch ); char pop(); }; void stack::init() { tos = 0; } void stack::push( char ch ) { if ( tos == SIZE ) { cout << "スタックはいっぱいです"; return; } stck[tos] = ch; tos++; } char stack::pop() { if ( tos == 0 ) { cout << "スタックは空です"; return 0; } tos--; return stck[tos]; } int main() { stack s1, s2; int i; s1.init(); s2.init(); s1.push('a'); s2.push('x'); s1.push('b'); s2.push('y'); s1.push('c'); s2.push('z'); for ( i=0; i<3; i++ ) cout << "s1をポップする:" << s1.pop() << endl; for ( i=0; i<3; i++ ) cout << "s2をポップする:" << s2.pop() << endl; return 0; }
コンパイル
g++ -o study21 study21.cpp
実行
s1をポップする:c s1をポップする:b s1をポップする:a s2をポップする:z s2をポップする:y s2をポップする:x