C++最速マスター その4
- 作者: グレゴリーサティア,ダウグブラウン,Gregory Satir,Doug Brown,望月康司,谷口功
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2001/11
- メディア: 単行本
- 購入: 9人 クリック: 147回
- この商品を含むブログ (29件) を見る
Index
inline
inlineは関数に付ける修飾子です。inline void echoError() {}のように設定すると関数をインライン展開します。インライン展開は呼び出しもとにコードそのものを埋め込んでしまうようなイメージです。これにより関数呼び出し処理の時間削減を行います。inlineはサイズの大きい関数またアドレス取得するような関数には適用ができません。
#include <iostream> using namespace std; // inline関数 inline int max( int x, int y ) { return ( x > y ) ? x : y; } int main() { int a = 10; int b = 11; cout << "-- inline func ---" << endl; // inline関数呼び出し cout << max( a, b ) << endl; return 0; }
iterator
basic_iterator
iteratorはpointerと同じような構造であり、vectorやmapなどのコンテナの中身を反復参照する時に使います。pointerと互換性を持っているので、pointerをiteratorとして使う事ができます。iteratorには幾つか種類があるので以下に簡単に整理します。またvectorとしてのiterator利用についてサンプルコードを載せます。
iterator 説明 InputIterator 読み込み専用アクセス。前方へのアクセス(++演算子はあるが、--演算子は無い)。istreamで利用 OutputIterator 書き込み専用アクセス。前方へのアクセス(++演算子はあるが、--演算子は無い)。ostreamで利用 ForwardIterator 読み書き可能アクセス。Input,OuputIteratorを組み合わせたもの BidirectionalIterator 読み書き可能アクセス。前方アクセスだけでなく後方も可能。(++、--演算子ともにある) 。list/set/mapで利用 RandomAccessIterator 読み書き可能、ランダムアクセス可能。++、--演算だけでなくランダムで指定もできる。array/vector/dequeで利用 #include<iostream> #include<vector> using namespace std; int main() { // int型のvectorを定義 vector<int> vect; //末尾に要素追加 vect.push_back( 1 ); vect.push_back( 100 ); vect.push_back( 2 ); // iterator for( vector<int>::iterator itr = vect.begin(); itr != vect.end(); itr ++ ) { cout << *itr << endl; } return 0; }実行結果
1 100 2 100reverse_iterator
reverse_iteartor、rbegin()、rend()を使う事によって双方向iteratorの動作を逆転させることが可能です。通常のiteratorは最初のノードから参照するのが基本ですが、reverse_iteratorを使って反転させます。
#include<iostream> #include<vector> using namespace std; int main() { // int型のvectorを定義 vector<int> vect; //末尾に要素追加 vect.push_back( 1 ); vect.push_back( 100 ); vect.push_back( 2 ); // reverse iterator for( vector<int>::reverse_iterator itr = vect.rbegin(); itr != vect.rend(); ++itr ) { cout << *itr << endl; } // randomaccess cout << vect[1] << endl; return 0; }実行結果
2 100 1 100const_iterator
通常のiterator、constで宣言をしたiterator、const_iteratorを使ったそれぞれの場合で可能な操作が異なります。以下の表に用途をまとめます。const_iteratorを使うと値の書き換えが不可能で、++演算による参照は可能なiteratorになります。読み込み専用だけであればconst_iteartorを使うと良いと思います。constで宣言した場合はポインタを使った値書き換えが可能ですが、前方/後方参照などが出来なくなります。const_iteartorを使う場合はその逆となり、値の書き換えが出来ず前方/後方参照ができるようになります。
type 値書き込み 前方/後方参照(++、--演算) iterator ○ ○ const ○ × const_iteartor × ○ #include<iostream> #include<vector> using namespace std; int main() { // int型のvectorを定義 vector<int> v; v.push_back( 1 ); v.push_back( 100 ); v.push_back( 2 ); // 通常のiterator vector<int>::iterator itr0 = v.begin(); *itr0 = 0; cout << "basic iterator" << endl; cout << *itr0 << endl; itr0++; cout << *itr0 << endl; // constで宣言したiterator const vector<int>::iterator itr1 = v.begin(); *itr1 = 1; // 以下はエラーとなる //itr1++; cout << "const" << endl; cout << *itr1 << endl; // const_iteratorを使った場合 vector<int>::const_iterator itr2 = v.begin(); // 以下はエラーとなる //*itr2 = 2; itr2++; cout << "const_iterator" << endl; cout << *itr2 << endl; return 0; }実行結果
basic iterator 0 100 const 1 const_iterator 100
pair
pairは2つの値の組み合わせで管理します。vectorとpairを組み合わせて使うとmapのような使い方ができます。第一の値を参照にするにはfirst、第二の値はsecondを指定します。
make_pair
通常pairを利用する時にはpair
のようにテンプレートの型を指定する必要がありますが、make_pairを使うとmake_pair( 'a', 'b' )のように型の記述を省略して直接値を入れることが出来ます。以下にサンプルコードと実行結果を載せます。 #include <iostream> #include <sstream> #include <vector> #include <string> #include <algorithm> using namespace std; string itos( int &i ) { ostringstream s; s << i; return s.str(); } int main() { typedef pair<int,int> int_pair; typedef pair<string,string> string_pair; vector<int_pair> v; vector<string_pair> sv; cout << "int vector" << endl; v.push_back( pair<int,int>(4,1) ); v.push_back( make_pair( 3, 1 ) ); v.push_back( make_pair( 2, 1 ) ); v.push_back( make_pair( 1, 2 ) ); // iteratorで抽出 for( vector<int_pair>::iterator itr = v.begin(); itr!= v.end(); itr++ ) { cout << "Key:" + itos( (*itr).first ) + " Value:" + itos( (*itr).second ) << endl; } // sort sort( v.begin(), v.end() ); cout << "after sort" << endl; for( vector<int_pair>::iterator itr2 = v.begin(); itr2!= v.end(); itr2++ ) { cout << "Key:" + itos( (*itr2).first ) + " Value:" + itos( (*itr2).second ) << endl; } cout << "string vector" << endl; sv.push_back( pair<string,string>( "d", "a" ) ); sv.push_back( make_pair( "c", "d" ) ); sv.push_back( make_pair( "b", "a" ) ); sv.push_back( make_pair( "a", "b" ) ); // iteratorで抽出 for( vector<string_pair>::iterator sitr = sv.begin(); sitr!= sv.end(); sitr++ ) { cout << "Key:" + (*sitr).first + " Value:" + (*sitr).second << endl; } // sort sort( sv.begin(), sv.end() ); cout << "after sort" << endl; for( vector<string_pair>::iterator sitr2 = sv.begin(); sitr2!= sv.end(); sitr2++ ) { cout << "Key:" + (*sitr2).first + " Value:" + (*sitr2).second << endl; } return 0; }実行結果
int vector Key:4 Value:1 Key:3 Value:1 Key:2 Value:1 Key:1 Value:2 after sort Key:1 Value:2 Key:2 Value:1 Key:3 Value:1 Key:4 Value:1 string vector Key:d Value:a Key:c Value:d Key:b Value:a Key:a Value:b after sort Key:a Value:b Key:b Value:a Key:c Value:d Key:d Value:a
cast
型変換 - Wikipedia
C++には独特なcastが定義されています。intからfloatへの変換やpinterを使ったものまで様々です。C++ではcastは使うべきでは無いと言われているようですが、一応紹介だけはします。
cast 説明 static_cast ビット変換キャスト、アップキャスト、型のテストをしないダウンキャスト dynamic_cast 安全なダウンキャスト const_cast constやvolatileを解除。mutable キーワードが使えない場合に使用 reinterpret_cast 全く型が異なる変換を行うキャスト static_cast
以下はintからdoubleに変換、constを外すためのcastです。
#include <iostream> #include <string> using namespace std; int main() { int i = 1; double d; char str; d = static_cast<double>( i ); cout << d << endl; // 以下は変換できない // str = static_cast<char>( i ); // cout << str << endl; return 0; }#include <iostream> #include <string> using namespace std; int main() { const int i = 1; int d; // error //i = 3; // constを解除するcast d = static_cast<int>( i ); d = 3; cout << d << endl; return 0; }dynamic_cast
継承している子クラスへのcast。
#include <iostream> #include <string> using namespace std; class Parent { public : virtual string echoString() {} }; class Child : public Parent { public : string echoString() { cout << "echo String" << endl; } }; int main() { Child child; Parent *parent = &child; Child *c = dynamic_cast<Child*>( parent ); if( c == NULL ) { cout << "failed down cast" << endl; return 1; } return 0; }const_cast
pointer関連のconstを解除します。
#include <iostream> #include <string> using namespace std; int main() { int i = 2; const int *p = &i; int *cp = const_cast<int*>( p ); cout << cp << endl; cout << *cp << endl; return 0; }reinterpret_cast
異なる型のPointer変換などに利用します。
#include <iostream> #include <string> using namespace std; int main() { int i = 10; int *ip = &i; double *dp; dp = reinterpret_cast<double*>( ip ); cout << dp << endl; return 0; }
Class
Javaを最速でマスターするための予備知識7項目 - Yuta.Kikuchiの日記
JavaにはNestedClass、InnerClass、AnnonymouseClass、LocalClassなどの種類が存在しましたがC++でも同じようにいくつか種類が用意されています。InnerClass
Classの内部に更にClassを定義する入れ子階層を実現できます。
#include <iostream> #include <string> using namespace std; // OuterClass class OuterClass { public : // InnerClass class InnerClass { public : string echoInnerMethod() { cout << "echo Inner Method" << endl; } InnerClass() { cout << "constructor InnerClass" << endl; } ~InnerClass() { cout << "destructor InnerClass" << endl; } }; OuterClass() { cout << "constructor OuterClass" << endl; } ~OuterClass() { cout << "destructor OuterClass" << endl; } }; int main() { OuterClass::InnerClass ic; ic.echoInnerMethod(); }実行結果
constructor InnerClass echo Inner Method destructor InnerClassLocal Class
関数の中に定義するClassです。他の関数からは呼び出しができません。呼び出そうとするとコンパイルエラーになります。error: ‘LocalClass’ was not declared in this scope
#include<iostream> #include<string> using namespace std; void localfunc() { class LocalClass { public : void echoString() { cout << "echo String" << endl; } }; LocalClass lc; lc.echoString(); } int main() { localfunc(); //error //LocalClass lc; //lc.echoString(); return 0; }実行結果
echo StringAnnonymous Class
AnnonymousClassにはメンバ変数は定義可能ですが、メンバ関数は定義できません。定義を行うとコンパイルでerror: an anonymous union cannot have function membersというエラーが出ます。 Annonymous Classのメンバ変数を呼び出す場合はOuterClassを経由します。
#include <iostream> #include <string> using namespace std; // OuterClass class OuterClass { public : // AnnonymouseClass class { public : int num; /* 関数は定義できない string echoInnerMethod() { cout << "echo Inner Method" << endl; } */ }; void setNumber( int n ) { num = n; } int getNumber() { return num; } OuterClass() { cout << "constructor OuterClass" << endl; } ~OuterClass() { cout << "destructor OuterClass" << endl; } }; int main() { OuterClass oc; oc.setNumber( 10 ); cout << oc.getNumber() << endl; }実行結果
constructor OuterClass 10 destructor OuterClass
etc
size_t
sizeof演算子で得られるデータ型をsize_tで表現します。実際にはunsigned longと同じようなデータ型のようです。
#include <iostream> using namespace std; int main() { int i = 10; size_t s = sizeof( i ); cout << s << endl; return 0; }