C++入門
目次
- はじめに
- 動作環境
- 対象者
- C++とは?
- 環境構築
- 最終目的
- コメント
- コーディング規約
- 基本構造
- ハローワールド
- コンパイル
- データ形式
- 演算子
- I/O
- 制御構造
- 関数
- ライブラリ STL (C++ Standard Template Library)
- クラス
- 継承(Inheritance)
- ポリモーフィズム(Polymorphism)
- Virtual Function (仮想関数)
- 抽象クラス
- インライン関数
- スタティックメンバ変数・スタティックメンバ関数
- リファレンス
- フレンド関数
- オーバーロード(Overload)
- 例外処理
- ネームスペース(名前空間)
- テンプレート
- C言語のリンケージ
- デバック
- 最後に
- 参考資料
はじめに
動作環境
対象者
C++とは?
環境構築
gcc3.3がインストールされていれば開発が出来ます。2.95の場合は、g++のフロントエンドが必要かもしれません。
最終目的
c++版の2cを作成するためC++の文法を理解します。C言語の開発時にヘッダファイルを確認する場合があるが、最近のLinuxやx86 Solaris9などでは、ヘッダファイルにC++の文法が含まれているため、そのレベルが解釈できるようにします。
コメント
// one line comment /// one line comment /* * multiple comments */
コーディング規約
多くの規約がありそうです。
基本構造
文法はC言語の上位互換があるので、C言語系の言語を学んでいれば同様に利用できます。
ハローワールド
[s-okita@stoc cpp]$ cat hello.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
cout << "Hello World!" << endl;
return 0;
}
コンパイル
[s-okita@stoc cpp]$ g++ -o hello hello.cpp [s-okita@stoc cpp]$ ./hello Hello World!
coutとendlを宣言するために<iostream>を呼んでいます。<iostream.h>などの.hサフィックスがつかないので注意してください。またJavaのPackageと同様にモジュールをnamespaceで宣言しています。
[s-okita@stoc cpp]$ file /usr/include/c++/3.2/iostream /usr/include/c++/3.2/iostream: C++ program text
namespaceの文をコメントアウトするgccではコンパイルできませんでした。以下がその時のログになります。
[s-okita@stoc cpp]$ g++ -o hello hello.cpp hello.cpp: In function `int main(int, char**)': hello.cpp:12: `cout' undeclared (first use this function) hello.cpp:12: (Each undeclared identifier is reported only once for each function it appears in.) hello.cpp:12: `endl' undeclared (first use this function) [s-okita@stoc cpp]$ ls hello.cpp hello2.cpp
g++コンパイラは、ファイル名にhello.cppなどのほかに、.cc .cp .cxx .cpp .Cなども標準でC++言語としてコンパイルが可能です。またJavaのようにクラス名とファイル名を一致させる必要はありません。
データ形式
クラス以外の型は、基本的にC言語、Java言語での型と同じです。また真偽を判断するためにbool型が存在します。boolean型ではないので注意してください。1バイトを表現するbyte型は存在しません。
プリミティブ型(Primitive types)
Linuxではbool型をtypedefでint型を再定義しています。それを確認したとのでその時のログが以下になります。
[s-okita@stoc cpp]$ cat primitive_types.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
char cval = 'a';
short sval = 1;
int ival = 1;
long lval = 100;
float fval = 1.1;
double dval = 1.1;
bool flag = true;
if ( flag == true )
{
cout << flag << endl;
}
bool test_bool = 1;
if ( test_bool )
{
cout << "bool type maybe was defined typedef statement.." << endl;
}
return 0;
}
[s-okita@stoc cpp]$ g++ -o primitive_types primitive_types.cpp
[s-okita@stoc cpp]$ ./primitive_types
1
bool type maybe was defined typedef statement..
byte型はC++言語では存在しないのですが、確認してみます。
[s-okita@stoc cpp]$ cat primitive_types.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
byte a = 0x00;
return 0;
}
[s-okita@stoc cpp]$ g++ -o primitive_types primitive_types.cpp
primitive_types.cpp: In function `int main(int, char**)':
primitive_types.cpp:6: `byte' undeclared (first use this function)
primitive_types.cpp:6: (Each undeclared identifier is reported only once for
each function it appears in.)
primitive_types.cpp:6: parse error before `=' token
定数(constants)
[s-okita@stoc cpp]$ cat constants.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
const int MAX_SIZE = 1024;
const char *P_CHAR_CONST = "HELLO";
cout << MAX_SIZE << endl;
cout << P_CHAR_CONST << endl;
// compile error
// MAX_SIZE = 200;
// NO COMPILE ERROR!!!
P_CHAR_CONST = "FUGA";
cout << P_CHAR_CONST << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o constants constants.cpp
[s-okita@stoc cpp]$ ./constants
1024
HELLO
FUGA
配列(Arrays)
- C++の配列はJavaのようにlengthメソッドを持ちません。
- インデックスのランタイムチェックがありません。
- java.lang.System#arraycopyのようなコピー関数が存在しません。
- 動的に配列のサイズが大きくなりません。
- STLに上記を解決するVectorが存在します。これはJavaのArray型に影響を与えたことが予想されます。
[s-okita@stoc cpp]$ cat arrays.cpp #include <iostream> using namespace std; void print_array(int ary [], int size) { for ( int i = 0; i < size; i++ ) { cout << ary[i] << endl; } } int main(int argc, char *argv[]) { /* newを呼ばなくてもメモリ領域を確保する。 */ int i_array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int i_multi_dimensional_arrays[10][20]; print_array(i_array, 10); // 配列を以下のようは宣言できない。 // int [10] i_array2; return 0; } [s-okita@stoc cpp]$ g++ -Wall -o arrays arrays.cpp arrays.cpp: In function `int main(int, char**)': arrays.cpp:16: warning: unused variable `int i_multi_dimensional_arrays[10][20] ' [s-okita@stoc cpp]$ ./arrays 0 1 2 3 4 5 6 7 8 9
列挙型(Enumerations)
[s-okita@stoc cpp]$ cat enumerations.cpp
#include <iostream>
using namespace std;
enum Week { Sun, Mon, Tues, Wednes, Thurs, Sat };
int main(int argc, char *argv[])
{
Week hoge;
hoge = Sun;
cout << hoge << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o enumerations enumerations.cpp
[s-okita@stoc cpp]$ ./enumerations
0
構造体(Structures)
[s-okita@stoc cpp]$ cat structure.cpp
#include <iostream>
using namespace std;
struct Status {
char name [64];
int age;
double weight;
};
int main(int argc, char *argv[])
{
Status myStat;
strncpy(myStat.name, "satoshi okita", sizeof(myStat.name));
myStat.age = 26;
myStat.weight = 55.0;
cout << myStat.name << endl;
cout << myStat.age << endl;
cout << myStat.weight << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o structure structure.cpp
[s-okita@stoc cpp]$ ./structure
satoshi okita
26
55
共用体(Union)
ポインタ(Pointers)
[s-okita@stoc cpp]$ cat pointer.cpp
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
/*
* p is pointer variable.
* x is valiable NO POINTER!!!
*/
int *px, x;
x = 100;
px = &x;
cout << *px << endl;
cout << px << endl;
px = NULL;
cout << px << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o pointer pointer.cpp
[s-okita@stoc cpp]$ ./pointer
100
0xbfffe700
0
newによるヒープ領域へのメモリ割り当て確認。C言語の場合、そのサイズ文mallocを使用しました。C言語とC++言語を混在しない場合は、基本的にnewキーワードでメモリ管理を行うべきだと思います。
[s-okita@stoc cpp]$ cat pointer_new.cpp
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, char argv[])
{
int *p;
p = new int;
*p = 200;
cout << *p << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o pointer_new pointer_new.cpp
[s-okita@stoc cpp]$ ./pointer_new
200
メモリアドレスの比較とメモリデータの比較
[s-okita@stoc cpp]$ cat pointer_expression.cpp
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
int *px;
int *py;
px = new int;
py = new int;
*px = 100;
*py = 100;
/* print address */
cout << "px addres=" << px << endl;
cout << "py addres=" << py << endl;
/* the pointer expression does NOT compare values */
if ( px != py )
{
cout << "ADDRESS COMPARE" << endl;
}
if ( *px == *py)
{
cout << "VALUE COMPARE:" << *px << endl;
}
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o pointer_expression pointer_expression.cpp
[s-okita@stoc cpp]$ ./pointer_expression
px addres=0x8049be0
py addres=0x8049bf0
ADDRESS COMPARE
VALUE COMPARE:100
メモリの割り当てにnew/deleteキーワードを使います。Java言語と異なりプリミティブ型にもnew/deleteを利用してヒープ領域へのメモリ割り当て/開放を行います。
[s-okita@stoc cpp]$ cat pointer_heap.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
/*
* c++言語はヒープ領域を割り当てはnew/deleteキーワードでおこなう。
*/
int *p;
p = new int;
*p = 100;
cout << *p << endl;
delete p;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o pointer_heap pointer_heap.cpp
[s-okita@stoc cpp]$ ./pointer_heap
100
WARNING memory leak!!
[s-okita@stoc cpp]$ cat pointer_leak.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int *p;
p = new int;
*p = 100;
p = NULL;
/* NULLを代入しただけで最初にnewでメモリを割り当てられた部分は開放していない*/
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o pointer_leak pointer_leak.cpp
[s-okita@stoc cpp]$ ./pointer_leak
配列型もnewキーワードでメモリを確保できるので実行してみます。
[s-okita@stoc cpp]$ cat ./array_new.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int *array;
array = new int [10];
for ( int i = 0; i < 10; i++ )
{
*(array + i) = i;
}
for ( int i = 0; i < 10; i++ )
{
cout << *(array + i) << endl;
}
delete [] array;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o array_new array_new.cpp
[s-okita@stoc cpp]$ ./array_new
0
1
2
3
4
5
6
7
8
9
演算子
C言語と同様です。
[s-okita@stoc cpp]$ cat chained.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int one = 1;
int two = 2;
int three = 3;
/* プリミティブ型を文字として解釈して表示する。*/
cout << one << two << three ;
return 0;
}
[s-okita@stoc cpp]$ g++ -o chained chained.cpp
[s-okita@stoc cpp]$ ./chained
123[s-okita@stoc cpp]$
I/O
[s-okita@stoc c++]$ cat io.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int x, y;
cin >> x;
cin >> y;
cout << "x=" << x << endl;
cerr << "y=" << y << endl;
}
[s-okita@stoc c++]$ g++ -Wall -o io io.cpp
[s-okita@stoc c++]$ ./io
1
2
x=1
y=2
[s-okita@stoc c++]$ cat file_io.cpp
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
void close_function(ifstream & v_ifs)
{
v_ifs.close();
if ( v_ifs.fail() == true )
{
cerr << "close error" << endl;
}
else
{
cerr << "close success" << endl;
}
}
int main(int argc, char *argv[])
{
ifstream ifs;
ifs.open("test.dat");
if ( ifs.fail() == true )
{
cerr << "unable to open" << endl;
}
else
{
cout << "open" << endl;
}
int tmp;
while ( ifs >> tmp )
{
cout << "tmp=" << tmp << endl;
}
close_function(ifs);
return 0;
}
[s-okita@stoc c++]$ g++ -Wall -o file_io file_io.cpp
[s-okita@stoc c++]$ ./file_io
unable to open
close error
制御構造
分岐
[s-okita@stoc c++]$ cat condition.cpp
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
bool aaa = false;
if ( aaa )
{
cout << "aaa is true" << endl;
}
if ( aaa == false )
{
cout << "aaa is false" << endl;
}
return 0;
}
[s-okita@stoc c++]$ g++ -Wall -o condition condition.cpp
[s-okita@stoc c++]$ ./condition
aaa is false
反復
[s-okita@stoc cpp]$ cat loop.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
/* Java言語と同様に必要な場所で宣言が可能 */
for ( int i = 0; i < 10; i++ )
{
cout << i << endl;
}
int j = 0;
while ( j++ < 10 )
{
cout << j << endl;
}
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o loop loop.cpp
[s-okita@stoc cpp]$ ./loop
0
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
10
関数
[s-okita@stoc cpp]$ cat function.cpp
#include <iostream>
using namespace std;
/* forward declaretion
* C言語のプロトタイプ宣言
*/
int print_hello();
int main(int argc, char *argv[])
{
int return_code;
return_code = print_hello();
if ( return_code == 1 )
{
cout << "SUCCESS" << endl;
}
else
{
cerr << "ERROR" << endl;
}
return 0;
}
int print_hello()
{
cout << "Hello" << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o function function.cpp
[s-okita@stoc cpp]$ ./function
Hello
ERROR
[s-okita@stoc cpp]$ ./function 1> /dev/null
ERROR
リファレンスとポインタ
アンパサンドを利用することでリファレンスという機能が使える。Java言語と同様。[s-okita@stoc c++]$ cat passing_mode.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
void passing_mode_by_value( int val )
{
val = 200;
cout << val << " in passing_mode_by_value." << endl;
}
void passing_mode_by_reference( int & ref )
{
ref = 500;
cout << ref << " in passing_mode_by_reference." << endl;
}
void passing_mode_by_pointer( int *p)
{
*p = 700;
cout << *p << " in passing_mode_by_pointer." << endl;
}
int main(int argc, char *argv[])
{
int x, y;
int *p_x;
int *p_y;
p_x = &x;
p_y = &y;
*p_x = 111;
*p_y = 999;
cout << "x=" << x << endl;
passing_mode_by_value( x );
cout << "x=" << x << endl;
passing_mode_by_reference( x );
cout << "x=" << x << endl;
passing_mode_by_pointer( p_x );
cout << "x=" << *p_x << endl;
return 0;
}
[s-okita@stoc c++]$ g++ -Wall -o passing_mode passing_mode.cpp
[s-okita@stoc c++]$ ./passing_mode
x=111
200 in passing_mode_by_value.
x=111
500 in passing_mode_by_reference.
x=500
700 in passing_mode_by_pointer.
x=700
ライブラリ STL (C++ Standard Template Library)
stringクラスを試してみる。
[s-okita@stoc cpp]$ cat stringTest.cpp
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string s1 = "HELLO";
string s2("HELLO");
cout << s1.size() << endl;
cout << s1.length() << endl;
if ( s1 == s2 )
cout << " true " << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o stringTest stringTest.cpp
[s-okita@stoc cpp]$ ./stringTest
5
5
true
Vectorクラスを試してみる
[s-okita@stoc cpp]$ cat vectorTest.cpp
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
vector<int> v;
cout << "size:" << v.size() << endl;
v.push_back(3);
v.push_back(5);
cout << "size:" << v.size() << endl;
for ( unsigned int i = 0; i < v.size(); i++ )
{
cout << v[i] << endl;
}
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o vectorTest vectorTest.cpp
[s-okita@stoc cpp]$ ./vectorTest
size:0
size:2
3
5
クラス
[s-okita@stoc cpp]$ cat class_ini.cpp
#include <iostream>
using namespace std;
/*
* クラスの宣言
*
* セミコロンが最後に必要なので注意することが必要です。また、コンストラクタで
* 初期化処理をおこない、デストラクタで後処理を行う。
*/
class class_ini {
int aaa;
public:
class_ini(); /* コンストラクタ */
~class_ini(); /* デストラクタ */
void show(); /* メンバー関数 */
};
class_ini::class_ini() {
cout << "invoked constructer" << endl;
}
class_ini::~class_ini() {
cout << "invoked destructer" << endl;
}
void class_ini::show() {
cout << " test show " << endl;
}
int main(int argc, char *argv[])
{
/* メモリの割り当て */
class_ini* obj = new class_ini();
/* 処理を実行 */
obj->show();
/* メモリの開放 */
delete obj;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o class_ini class_ini.cpp
[s-okita@stoc cpp]$ ./class_ini
invoked constructer
test show
invoked destructer
コンストラクタに引数をつけてみる
[s-okita@stoc cpp]$ cat constructor2.cpp
#include <iostream>
#include <string>
using namespace std;
class Person {
string name;
int age;
public:
Person();
Person(string vname, int vage);
~Person();
void show();
};
Person::Person()
{
}
Person::Person(string vname, int vage)
{
name = vname;
age = vage;
}
Person::~Person()
{
cout << "destructor" << endl;
}
void Person::show()
{
cout << name << endl;
cout << age << endl;
}
int main(int argc, char *argv[])
{
Person *pObj = new Person("Satoshi", 26);
pObj->show();
delete pObj;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o constructor2 constructor2.cpp
[s-okita@stoc cpp]$ ./constructor2
Satoshi
26
destructor
継承(Inheritance)
[s-okita@stoc cpp]$ cat inheritance.cpp
#include <iostream>
using namespace std;
/* 継承の元となるクラスを基本クラス(Base Class)と呼ぶ */
class BaseClass {
double height;
double weight;
public:
BaseClass();
void show();
};
BaseClass::BaseClass()
{
cout << "load constructor" << endl;
height = 1.1;
weight = 2.2;
}
void BaseClass::show()
{
cout << height << endl;
cout << weight << endl;
}
/* 派生クラスと呼ぶ(DerivedClass)
* publicにBaseClassクラスを継承する。
*/
class DerivedClass : public BaseClass {
char blood;
public:
DerivedClass();
void showBlood();
};
DerivedClass::DerivedClass() {
cout << "load constructor" << endl;
blood = 'B';
}
void DerivedClass::showBlood()
{
cout << blood << endl;
}
int main(int argc, char *argv[])
{
DerivedClass *pDC = new DerivedClass();
pDC->show();
pDC->showBlood();
delete pDC;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o inheritance inheritance.cpp
[s-okita@stoc cpp]$ ./inheritance
load constructor
load constructor
1.1
2.2
B
ポリモーフィズム(Polymorphism)
Virtual Function (仮想関数)
[s-okita@stoc cpp]$ cat DynamicOverride.cpp
/*
* Dynamic Override.cpp
* ポリモーフィズムを実現する機能。仮想関数(Virtual Function)と呼ぶ
*/
#include <iostream>
using namespace std;
class DynaBase
{
public:
virtual void printHello ()
{
cout << "hello" << endl;
}
void show ()
{
cout << "fuga" << endl;
}
};
class GoodbyeClass:public DynaBase
{
public:void printHello ()
{
cout << "goodbye" << endl;
}
void show ()
{
cout << "hoge" << endl;
}
};
int
main (int argc, char *argv[])
{
DynaBase daObj;
GoodbyeClass gcObj;
DynaBase *pDynaBase;
pDynaBase = &daObj;
/* 実行時にオブジェクトを確認してそのメンバ関数を呼び出す */
pDynaBase->printHello ();
/* コンパイル時にベースクラスのメンバ関数に確定される */
pDynaBase->show ();
pDynaBase = &gcObj;
/* 実行時にオブジェクトを確認してそのメンバ関数を呼び出す */
pDynaBase->printHello ();
/* コンパイル時にベースクラスのメンバ関数に確定される */
pDynaBase->show ();
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o DynamicOverride DynamicOverride.cpp
[s-okita@stoc cpp]$ ./DynamicOverride
hello
fuga
goodbye
fuga
抽象クラス
[s-okita@stoc cpp]$ cat AbstructClass.cpp
/* JavaでのAbstructクラスまたはInterfaceを実現するためには
* C++では仮想関数を利用する。
*/
#include <iostream>
#include <string>
using namespace std;
/*
* 抽象クラスになる例
*/
class AbstructClass {
public:
/* 抽象化するためにabstructキーワードは存在しない
* それを実現するために関数の宣言時に=0を指定する。
*/
virtual void show(string name) = 0;
};
/*
* 抽象クラスを継承する場合は、必ずベースクラスの関数を実装しなければならない
*/
class ComclateClass : public AbstructClass {
public:
void show(string name)
{
cout << name << endl;
}
};
int main(int argc, char *argv[])
{
AbstructClass *pAC = new ComclateClass;
pAC->show("polymorphism");
delete pAC;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o AbstructClass AbstructClass.cpp
[s-okita@stoc cpp]$ ./AbstructClass
polymorphism
インライン関数
インライン関数は、C言語のマクロ定義の代用に出来る。関数呼び出しのオーバーヘッドがないためである。 Java言語ではメソッドにfinal修飾子をつけることでインライン化が可能である。パフォーマンスを求める時に 利用できる。Javaのようにクラス定義内に関数を書くとinline関数となる。
[s-okita@stoc cpp]$ cat inline.cpp
#include <iostream>
using namespace std;
/* インライン関数
* * C++言語では、一般にマクロ定義をインライン関数でおこなう。
* */
inline int func(int x)
{
return x * 100;
}
class TestClass {
int status;
public:
TestClass();
~TestClass();
void show();
/* インラインメンバ関数
* * Javaでいうfinalキーワードを実装しているのと同様
* */
void showInline()
{
cout << "write as java code, inline member function!" << endl;
}
/* インラインキーワードを使ってインラインメンバ関数を
* * 記述する例
* */
inline void showInline2()
{
cout << "write inline keyword." << endl;
}
};
TestClass::TestClass()
{
cout << "load constructor" << endl;
status = 100;
}
TestClass::~TestClass()
{
cout << "load destructor" << endl;
}
void TestClass::show()
{
cout << status << endl;
cout << func(100) << endl;
}
int main(int argc, char *argv[])
{
TestClass *pObj;
pObj = new TestClass();
pObj->show();
pObj->showInline();
pObj->showInline2();
delete pObj;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o inline inline.cpp
[s-okita@stoc cpp]$ ./inline
load constructor
100
10000
write as java code, inline member function!
write inline keyword.
load destructor
スタティックメンバ変数・スタティックメンバ関数
[s-okita@stoc cpp]$ cat static.cpp
#include <iostream>
#include <string>
using namespace std;
class StaticTestClass {
string username;
public:
StaticTestClass();
StaticTestClass(string name);
static string company_name; /* スタティックメンバ変数の定義*/
void showPrivateData();
static long getUniqueSerialNumber();
};
/* スタティックメンバ変数は、クラス定義の後で再宣言しないと使えない */
string StaticTestClass::company_name = "R&D, inc";
StaticTestClass::StaticTestClass()
{
username = "";
}
StaticTestClass::StaticTestClass(string username)
{
/* Java言語と同様thisキーワードが使える
* * 自分のオブジェクトを参照できる
* * ただ、ポインタと同様なため->アロー演算子を利用する事
* */
this->username = username;
}
void StaticTestClass::showPrivateData()
{
cout << username << endl;
}
long StaticTestClass::getUniqueSerialNumber()
{
/* 本来は乱数などでシリアルを生成する */
return 100 * 20;
}
int main(int argc, char *argv[])
{
StaticTestClass *pObj = new StaticTestClass("satoshi");
pObj->showPrivateData();
cout << StaticTestClass::company_name << endl;
cout << StaticTestClass::getUniqueSerialNumber() << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o static static.cpp
[s-okita@stoc cpp]$ ./static
satoshi
R&D, inc
2000
リファレンス
C++では、データを渡す際にリファレンスという機能がある。ポインタとは異なる。
[s-okita@stoc cpp]$ cat references.cpp
/* references.cpp
*
* リファレンスは、変数の別名Aliasとして使われる
* 宣言には&をつかう。
*/
#include <iostream>
using namespace std;
class TestClass {
public:
TestClass(string name);
string name;
};
TestClass::TestClass(string name)
{
this->name = name;
}
int main(int argc, char *argv[])
{
/* 実体の作成 */
TestClass ts("satoshi");
/* リファレンスの作成 */
TestClass &ref = ts;
cout << ref.name << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o references references.cpp
[s-okita@stoc cpp]$ ./references
satoshi
値渡しのサンプル
[s-okita@stoc cpp]$ cat ByValue.cpp
#include <iostream>
#include <string>
using namespace std;
class TestClass
{
string name;
public:
TestClass ();
void setName (string name);
string getName ();
};
TestClass::TestClass ()
{
this->name = "default";
cout << "constructor data set: " << name << endl;
}
void
TestClass::setName (string name)
{
this->name = name;
}
string
TestClass::getName ()
{
return this->name;
}
void
testByValue (TestClass ts)
{
/* 値渡しのためデータは反映されない */
ts.setName ("aaa");
}
int
main (int argc, char *argv[])
{
TestClass ts;
testByValue (ts);
cout << ts.getName () << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o ByValue ByValue.cpp
[s-okita@stoc cpp]$ ./ByValue
constructor data set: default
default
参照渡しのサンプル(C++機能のリファレンスを使う)
[s-okita@stoc cpp]$ cat ByReferences.cpp
/* C/C++言語では、呼び出し元のデータを変更するためにはアドレスの参照渡し
* する必要がある。C++では、ポインタを使わずにアドレスを渡せる
* これは、サンプルを見てもらえば分かるが関数を使う側はアドレスを渡すか、実体を
* 渡すか意識しなくて良い。Java言語のリファレンス機能と同様。
* Javaはこれをさらに発展させて&記号を使っていない。
*/
#include <iostream>
#include <string>
using namespace std;
class RefClass
{
string name;
public:
RefClass (string name);
void show ();
};
RefClass::RefClass (string name)
{
this->name = name;
cout << "constructor" << endl;
}
void
RefClass::show ()
{
cout << name << endl;
}
void
testRefFunction (RefClass & ref)
{
ref.show ();
}
int
main (int argc, char *argv[])
{
RefClass rc ("satoshi");
testRefFunction (rc);
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o ByReferences ByReferences.cpp
[s-okita@stoc cpp]$ ./ByReferences
constructor
satoshi
フレンド関数
privateなメンバ変数にアクセスするには、通常そのクラスにpublicなメンバ関数を作る。これはJavaやRubyなど多くのオブジェクト言語では同様の機能を持っている。C++には、この方法以外にもフレンドという機能がある。
[s-okita@stoc cpp]$ cat friend.cpp
/* friend.cpp */
#include <iostream>
#include <string>
using namespace std;
class TestClass {
string name;
friend void showPrivateData(TestClass &ref);
public:
TestClass(string name);
};
TestClass::TestClass(string name)
{
this->name = name;
}
void showPrivateData(TestClass &ref)
{
cout << ref.name << endl;
}
int main(int argc, char *argv[])
{
TestClass ts("okita");
TestClass &ref = ts;
showPrivateData(ref);
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o friend friend.cpp
[s-okita@stoc cpp]$ ./friend
okita
オーバーロード(Overload)
[s-okita@stoc cpp]$ cat overload.cpp
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int i = 0;
double trouble = 99.9;
char a_character = 'a';
char b_character = 'b';
/*
* cout << プリミティブ型 << endl;
* C言語と異なり、どのようなプリミティブ型でも同じ書き方で表示できる
*/
cout << i << endl;
cout << trouble << endl;
cout << a_character << endl;
cout << b_character << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -o overload overload.cpp
[s-okita@stoc cpp]$ ./overload
0
99.9
a
b
例外処理
Java言語と同様、throw, try, catchキーワードで実装する。
[s-okita@stoc cpp]$ cat Exception.cpp
/* 初期のC++では、例外処理を実装していなかったが
* 現在のC++では、例外処理を実装できる。C言語などでは、通常の処理を
* コーディングしている途中にエラー時の処理を記述していた傾向があるため
* 可視性が悪かった。それを防ぐ機能。
* 基本的にJavaの例外処理を同様である。
*/
#include <iostream>
#include <string>
using namespace std;
char *errorMessage = "Exception : isNotZero";
class ExceptionSample
{
public:int isZero (int i) throw (char *);
};
/* ゼロであれば、100を返すサンプル関数
* エラー処理をExceptionで実装しているため戻り値をエラー用に使わなくてすむ
*/
int
ExceptionSample::isZero (int i)
throw (char *)
{
cout << "isZero start" << endl;
if (i != 0)
{
throw errorMessage;
}
return 100;
}
int
main (int argc, char *argv[])
{
ExceptionSample *es = new ExceptionSample;
int testData = 100;
try
{
es->isZero (testData);
}
catch (char *errorMessage)
{
cout << "char *" << endl;
cout << errorMessage << endl;
}
catch (...)
{
cout << "..." << endl;
cout << "finally keyword in Java." << endl;
}
delete es;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o Exception Exception.cpp
[s-okita@stoc cpp]$ ./Exception
isZero start
char *
Exception : isNotZero
ネームスペース(名前空間)
[s-okita@stoc cpp]$ cat namespace.cpp
/* Java言語のpackageに相当する機能をnamespaceで実現する */
#include <iostream>
#include <string>
/* coutを利用するためにstdを宣言 */
using namespace std;
namespace print_pkg
{
string print ()
{
return "hoge";
}
}
/* print_pkgの利用を宣言する。これによりprint関数が使える */
using namespace print_pkg;
int
main (int argc, char *argv[])
{
/* using namespace print_pkg;が存在しないとエラー */
cout << print () << endl;
cout << print_pkg::print () << endl;
/* using namespace std;が宣言していない場合は、以下のように
* ネームスペース::オブジェクトのように利用しなければならない。
*/
std::cout << "test" << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o namespace namespace.cpp
[s-okita@stoc cpp]$ ./namespace
hoge
hoge
test
テンプレート
ポリモーフィズムを実現する機能の1つです。テンプレートはライブラリを作成する際に非常に重宝します。JavaでもJDK5.0からgenericsという名称でテンプレート機能が実装されました。
[s-okita@stoc cpp]$ cat template_function.cpp
#include <iostream>
#include <string>
/* テンプレート機能は、オーバーロードの代用として利用できる。
* また、テンプレートは、コンパイル時にコンパイラが、
* その型に合ったインスタンスを
* 生成するという特徴がある。
*/
using namespace std;
template < class T > T add (T & l, T & r)
{
return l + r;
}
int
main (int argc, char *argv[])
{
int i = 100;
int j = 200;
cout << add (i, j) << endl;
string first = "satoshi";
string last = "okita";
cout << add (first, last) << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o template_function template_function.cpp
[s-okita@stoc cpp]$ ./template_function
300
satoshiokita
[s-okita@stoc cpp]$ cat template_class.cpp
#include <iostream>
#include <string>
using namespace std;
/* クラステンプレート */
template < class T > class XX
{
public:
T square (T t)
{
return t * t;
}
};
/* 引数のあるクラステンプレート */
template < class T, int n > class X
{
public:
T add ()
{
return n * 100;
}
};
int
main (int argc, char *argv[])
{
XX < int >variable1;
int i = 100;
cout << variable1.square (i) << endl;
X < float, 22 > x1;
cout << x1.add () << endl;
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -O2 -o template_class template_class.cpp
[s-okita@stoc cpp]$ ./template_class
10000
2200
C言語のリンケージ
C言語で記述したオブジェクトファイルをC++言語に結合するにはexternキーワードを利用する
[s-okita@stoc cpp]$ cat clink.c
#include <stdio.h>
void hello()
{
printf("hello\n");
}
[s-okita@stoc cpp]$ gcc -Wall -O2 -c clink.c
[s-okita@stoc cpp]$ cat cpplink.cpp
#include <iostream>
/* C言語で作られている事をexternキーワードで指定する */
extern "C" {
void hello();
}
int main(int argc, char *argv[])
{
hello();
return 0;
}
[s-okita@stoc cpp]$ g++ -Wall -o cpplink cpplink.cpp clink.o
[s-okita@stoc cpp]$ ./cpplink
hello
デバック
最後に
参考資料
Learning a New Programming Language: C++ for Java Programmers(英語)
