2000/4/21 (HEP初心者の為の)C++入門 1
(HEP初心者の為の) C++入門
Nobu KatayamaKEK
Apr. 21, 2000Belle/Software2000, Tokyo
2000/4/21 (HEP初心者の為の)C++入門 2
目次
• 前置き(データ解析とは)
• C++について
• クラスをつくる(簡単な文法の解説を含む)
• 継承する(簡単な文法の解説を含む)
• C++に関する「知っておきたい事」集
2000/4/21 (HEP初心者の為の)C++入門 3
BELLEの文脈でデータ解析とは
• 実験データから粒子の寿命、崩壊の分岐比等を求める
• 実験データから得られる様々な分布が仮説に合っているか検証する
• 何か新しい、予想もしていない様な事が起きていないか探す
2000/4/21 (HEP初心者の為の)C++入門 4
データ解析の流れ
• 自分の探している事象の起こっているイベントを見つける
• 自分の探している事象を含んでいると思われるイベントについて、様様な分布を取り、統計的に処理する
• 分岐比、寿命等のパラメタを算出する
(「イベント」とは、一回の電子陽電子衝突の際に収集されるデータの事。現在一日に1、500万イベントくらい収集しています)
2000/4/21 (HEP初心者の為の)C++入門 5
実験データの処理
• データ解析等に使うため、実験データ(イベント)を使い、粒子の軌跡を立体再構成する
• (仮説に対して確率的に)粒子の同定を行う
• 模擬実験データを作る
• 「立体再構成する」時に使う定数を算出する
• 様々な統計量を計算し、時間的変化がない事を確認し、実験がうまく続いている事を確認する
2000/4/21 (HEP初心者の為の)C++入門 6
データ解析とプログラミング言語
• 大量の実験データ→数個のヒストグラム
• 実験データを
– 変換する
– 集約する
– 組み合わせる
– 取捨選択する
– 最適化する
– 創造する(模擬実験データの場合)
– 表示、表現する
2000/4/21 (HEP初心者の為の)C++入門 7
プログラミング言語の歴史
• FORTRAN→II→IV→66→77→90→95→• C→C89(ISO)(→HPC)• C++(ISO, 1999年頃に標準化された)• Others (BASIC, Pascal, Smalltalk, Java,,,)• 尚WEBとHTMLは、高エネルギー物理学の研究所の一つである、欧州合同原子核研究機関(CERN)に於いて発明され、スタンフォード線形加速器研究所(SLAC )で初めてウインドウベースのブラウザーが作られました
2000/4/21 (HEP初心者の為の)C++入門 8
なぜC++を使うか?
• 過去30年以上、FORTRANを使ってきた
• 高エネルギー物理学実験がより大掛かりかつ精密になり、データ解析が格段に複雑になった
• 92年頃からオブジェクト指向の言語は素晴らしいといわれるようになった
• UNIXを使うようになった
2000/4/21 (HEP初心者の為の)C++入門 9
C++の何が良いか(私見)
• 名前の長さに制限がない(C)
• データ構造をもつ事ができる(C)
• UNIXと親和性が良い(C)
• 型を自分(たち)で定義できる
• データを隠す事ができる
• Strong typingである
• データ構造を初期化するコードを自然に書ける
• Freewareのコンパイラがある
2000/4/21 (HEP初心者の為の)C++入門 10
C++の使いにくい所
• 文法が非常に複雑である
• コンパイラがまだ未完成である
• コンパイルが遅い
• 多重ループが作りにくい(特にSTLで)
• オブジェクトIOが言語あるいは標準ライブラリには定義されていない
• HEPのライブラリとして使えるものが少ない(CLHEP、GEANT4のみ?)
2000/4/21 (HEP初心者の為の)C++入門 11
C++の文法
• 基本の文法以前の事
• クラス
• 式(expressions)と文(statements)• 配列、ポインタ、アドレス、レファレンス
• スコープと記憶領域
• 標準ライブラリ
• テンプレート、標準テンプレートライブラリ
2000/4/21 (HEP初心者の為の)C++入門 12
初めてのC++プログラム
$ cat > a.cc #プログラムをファイルに書く#include <iostream>// print out “Hello Belle” to stdout
int main(void) {std::cout << “Hello Belle” << std::endl;
return 0;
}^D
$ c++ a.cc #コンパイルする
$ a.out #実行する
2000/4/21 (HEP初心者の為の)C++入門 13
基本の文法以前の事
• main関数
• 文字セット
• コメント行
• #include• 標準出力
• エディタとシェル
• 実行形式のファイルを作る
2000/4/21 (HEP初心者の為の)C++入門 14
正しいC++の文法
• C++の文法を正しく論理的に説明しようとすると、ISOの規格書にあるように、千ページ程度の本となる(もちろん1時間ではカヴァー出来ない)
• コンパイラが厳しいので、かなりの間違いはコンパイラが気づいてくれる(甘いコンパイラもある)
• ただし、コンパイラの気づかない、重要なコーディングの間違いもたくさんある
• 習うより慣れろ、である
• 細かい文法については自分で読みやすい本を買って座右に置いておくこと
2000/4/21 (HEP初心者の為の)C++入門 15
自分で型(type)を作る
• 今までのプログラミング言語では型は言語によって与えられていて、自分で作ることは出来なかった
• Cでは整数, 浮動小数点数, 文字型のみ
• C++では「クラス(class)」を宣言する事により自分
の作りたい型を新たに作る事が出来る
• ヘッダーファイルを#includeする事により他人の
作った型を使うことが出来る
2000/4/21 (HEP初心者の為の)C++入門 17
Line クラス と Point クラス
class Point {
Point(double x, double y);
};
class Line {
Line(const Point &p1,
const Point &p2);
Point cross(const Line &) const;
};
2000/4/21 (HEP初心者の為の)C++入門 18
関数と引数
• 関数には引数と戻り値がある
• どちらもなくても良い– 引数或いは戻り値がない場合、void型を引く、
返すという
• 関数を使う、或いは定義する為にはどんな型の引数がいくつあるか、戻り値の型は何かを宣言しなくてはならない
2000/4/21 (HEP初心者の為の)C++入門 19
データメンバーとメンバー関数
• クラスの定義では、データメンバー(メンバー変数)を定義し、メンバー関数を宣言する
• C++では、能率の良いバイナリー(実行形式のファイル)を作るためにコンパイル時にデータメンバーのサイズがわかっていなければならない。従って、クラスを定義している時点で定義されていない型をメンバー変数或いは引数、戻り値として使う事はできない
• メンバー(変数と関数)のアクセス権限を制限する事が出来る(public,protected,private)
2000/4/21 (HEP初心者の為の)C++入門 20
main関数
� PointとLineを使う。使い方さえ知っていれば、PointクラスとLineクラスがどうやって実装されているかは知る必要がないint main(void) {
Point p0(1.0, 3.0), p1(2.0, 5.0);Point p2(1.0, 5.0), p3(2.0, 3.0);
Line l0(p0, p1), l1(p2, p3);Point v(l0.cross(l1));
std::cout << v << std::endl;
}
2000/4/21 (HEP初心者の為の)C++入門 21
変数の定義とコンストラクタ
Point p0(1.0,3.0), p1(2.0,5.0);
• 上の文はPointクラスの変数( 変数名はp0,p1)を、それぞれの初期値((1.0,3.0)と(2.0,5.0))で定義している
• p0,p1はPointクラスのオブジェクトと呼ばれる
• 初期値の設定はPointクラスのコンストラクタ(関数)を呼ぶことによって行われる
• これらのオブジェクトはスコープの範囲内で有効であり、スコープを外れると消滅する
2000/4/21 (HEP初心者の為の)C++入門 22
メンバー関数
Point v(l0.cross(l1));
• はLineクラスのオブジェクトl0に対してメンバー関数crossを呼び出し(関数の引数はl1 )、その戻り値によってPointクラスの変数vを初期化して
いる
• 同じクラスのオブジェクトを引数とするコンストラクタPoint(const Point&)は自動的に定義される(これには注意が必要である)
2000/4/21 (HEP初心者の為の)C++入門 23
const
• constキーワードは良いC++のプログラムでは多用される
• constキーワードは、コンパイラに、変数の値がその変数の生存期間中に変化しない事を知らせる
• constメンバー関数はその関数が呼び出されている間にはオブジェクトが変化しないことをコンパイラに知らせる
• 従って、constオブジェクトに対してはconstメンバー関数しか呼び出すことができない
2000/4/21 (HEP初心者の為の)C++入門 24
Pointクラスの定義
class Point {public:
Point(double x, double y) : m_x(x),m_y(y) {}
double x() const { return m_x; }
double y() const { return m_y; }private:
double m_x;double m_y;
};
2000/4/21 (HEP初心者の為の)C++入門 25
クラスの名前と変数名
• 名前の付け方は自由だが、統一されていると読みやすい。通常
– クラスの名前は先頭文字を大文字にする
– メンバー変数の名前はm_で始める
– 定数は全部大文字
– その他は全部小文字
– 変数名は数行以上にわたって使われる時は名前を見て大体意味の判るようにつける
程度には使い分ける。特にチェックはしていません
2000/4/21 (HEP初心者の為の)C++入門 26
Pointクラスの実装
inline std::ostream &operator<<(std::ostream &s,
const Point &x){
s << “(” << x.x() << “,”
<< x.y() << “)” << std::endl;
return s;
}
� iostream(入出力)についてはおまじないのような物
だと思ってこのまま使うこと
� この関数はメンバー関数ではないのでPoint::はいら
ない
2000/4/21 (HEP初心者の為の)C++入門 27
inlineとヘッダーファイル
• メンバー関数の実装(implementation)は通常ソースファイル(.cc)で行い、ソースファイルはコンパ
イルされて、ライブラリが作られる
• 軽い、あるいは多用されると思われる簡単な関数についてはヘッダーファイルの中で実装しても良い(ただし、inline関数を濫用しないこと)
• ヘッダーファイル内で実装するときはinlineキー
ワードを、また、クラスの定義の外で実装する時はスコープ解決演算子(クラス名::)をつける
2000/4/21 (HEP初心者の為の)C++入門 28
Lineクラスの定義
class Line {
public:
Line(const Point &p1,
const Point &p2);
Point cross(const Line &) const;
private:
double m_a;
double m_b;
};
2000/4/21 (HEP初心者の為の)C++入門 29
Lineクラスの実装(I)
Line::Line(const Point &p1,const Point &p2) {
if(p1.x()==p2.x()) {std::cerr << “Not implemented”
<< std::endl;
exit(1);}
m_a=(p2.y()-p1.y())/(p2.x()-p1.x());m_b=p1.y() - m_a * p1.x();
}
2000/4/21 (HEP初心者の為の)C++入門 30
C++の演算子(operator)
• 代入(=、+=、-=、*=、、、)
• 算術(+、-、*、/、、、)
• 関係(==、!=、<、>)
• 論理(&&、||)
• キャスト
• その他(単項、new、delete、?:、カンマ、シフト、ビット論理、、、)
• 優先順位がわかりにくい場合も多いので「()」を使用して(自分も含めた)読み手にわかりやすいプログラムを書くこと
2000/4/21 (HEP初心者の為の)C++入門 31
if 文(文と式)
• if (式) 文 else 文– 「式」を評価して真(true)であれば直後の「文」が、偽(false)であればelseの直後の文が実行される。ただしelse以下はなくても良い
– ==と=を混同しない事
• 文と{}
– {}の中に複数の文を入れることができる
– {}でくくられたもの全体も一つの文である
2000/4/21 (HEP初心者の為の)C++入門 32
Lineクラスの実装(II)
Point Line::cross(const Line &l) const{if(m_a==l.m_a) {
std::cerr << “Does not cross”<< std::endl;
exit(1);
}double x=(m_b-l.m_b)/(l.m_a-m_a);
double y=m_a * x + m_b;return Point(x,y);
};
2000/4/21 (HEP初心者の為の)C++入門 33
宿題
• Y軸に平行な線についても動作するようにLineクラスの実装を変更しなさい
x
0
y
c
インターフェースを変更する必要はない!!
2000/4/21 (HEP初心者の為の)C++入門 34
もう少し実験に近づくとLine
Hit(Point)
Detector
Vertex(Point)
L0
p0
p2
p4
p1
p5
p3
D1
D3
D0 D2
h1 h3
h0
h2
L1
2000/4/21 (HEP初心者の為の)C++入門 35
測定点と測定器
class Measurement {
Measurement(double v);
double value() const;
};
class Detector {
Detector(const Point &begin,
const Point &end);
Point getPoint(const Measurement &)const;
};
端点
測定点
端点
2000/4/21 (HEP初心者の為の)C++入門 36
main関数
Point p0(3,0), p1(3,-3), p2(3,3);
Point p3(6,0), p4(6,-3), p5(6,3);
Detectpr d0(p0, p1), d1(p0, p2);
Detector d2(p3, p4), d3(p3, p5);
Measurement m0(0.1),m1(0.3),m2(0.2),m3(0.4);
Point h0(d0.getPoint(m0)), h1(d1.getPoint(m1));
Point h2(d2.getPoint(m2)), h3(d3.getPoint(m3));
Line l0(h0,02), l1(h1,h3);
Point v = l0.cross(l1);
2000/4/21 (HEP初心者の為の)C++入門 37
Detectorクラスの定義
class Detector {
public:
Detector(const Point &begin,
const Point &end);
Point getPoint(const Measurement &) const;
private:
Point m_b, m_e;
};
2000/4/21 (HEP初心者の為の)C++入門 38
Detectorクラスの実装 (I)
Detector::Detector(const Point &begin,
const Point &end):
m_b(begin), m_e(end) {
if(m_b.x()!=m_e.x()) {
std::cerr << “Not implemented”
<< std::endl;
exit(1);
}
}
2000/4/21 (HEP初心者の為の)C++入門 39
Detectorクラスの実装 (II)
Point Detector::getPoint(const Measurement&m)const {
double v = m.value();if(v<0.0 || v>1.0) {
std::cerr << “Invalid input value ”
<< v << std::endl;exit(1);
}double y = m_b.y()+v*(m_e.y()-m_b.y());
return Point(m_b.x(), y);}
2000/4/21 (HEP初心者の為の)C++入門 41
HitとVertexとは
• Hit型とVertexをPoint型から継承する.• Hit型はDetectorの方向に沿って測定誤差
がある
• Vertex型は測定誤差の伝播によって全方
向に誤差をもつ Point
Hit Vertex
2000/4/21 (HEP初心者の為の)C++入門 42
Hitクラス
class Hit : public Point {
public:
Hit(const Point &x, double dx);
double dx() const { return m_dx; }
private:
double m_dx;
};
HitクラスはPointクラスを継承する
Pointクラスのメンバー関数はそのまま使うことが出来る
2000/4/21 (HEP初心者の為の)C++入門 43
Vertexクラス
class Vertex : public Point {
public:
Vertex(double x, double y,
double dxx, double dxy,
double dyy);
private:
double m_dxx, m_dxy, m_dyy;
};
2000/4/21 (HEP初心者の為の)C++入門 44
Trackクラスの定義class Track : public Line {public:
Track(const Hit &h1, const Hit &h2);void addHit(const Hit&);
Vertex cross(const Track &);
private:void add(const Hit&);
void calc();double m_dada, m_dadb, m_dbdb;
double m_sxx, m_sx, m_sy, m_sxy};
2000/4/21 (HEP初心者の為の)C++入門 45
Trackクラスの実装(I)Track::Track(const Hit &h0,const Hit &h2):Line(h0, h1) {
m_sxx = m_sx = m_sxy = m_s = 0.0;add(h0);
add(h1);
calc();}
Track::addHit(const Hit &h) {add(h);
calc();}
2000/4/21 (HEP初心者の為の)C++入門 46
Trackクラスの実装(II)
void Track::add(const Hit &h) {
double dxxi = 1.0/h.dx()/h.dx();
m_sxx += h.x()*h.x()*dxxi;
m_sx += h.x()*dxxi;
m_sxy += h.x()*h.y()*dxxi;
m_s += dxxi;
}
2000/4/21 (HEP初心者の為の)C++入門 47
Trackクラスの実装(III)
Track::calc() {
set_a((m_s*m_sxy-m_sx*m_sy)/
(m_s*m_sxx-m_sx*m_sx);
set_b((m_sy*m_sxx-m_sxy*m_sx)/
(m_s*m_sxx-m_sx*m_sx);
// 宿題 m_dada, m_dadb and m_dbdb
// を自分で計算すること
}
2000/4/21 (HEP初心者の為の)C++入門 48
Lineクラスを変更する
class Line {
…
protected:
void set_a(double a) { m_a = a; }
void set_b(double b) { m_b = b; }
…
protected:によってこれらの関数を呼ぶ事が出来るのは
Lineクラスを継承したクラスのメンバー関数のみ
2000/4/21 (HEP初心者の為の)C++入門 49
Hit型とVertex型の実装
• これは宿題
• メイン関数は誤差を含まなかった場合と殆ど変更する必要はないMeasurement m0(0.1),m1(0.3),m2(0.2),m3(0.4);
Hit h0(d0.getHit(m0)), h1(d1.getHit(m1));
Hit h2(d2.getHit(m2)), h3(d3.getHit(m3));
Track t0(h0,02), t1(h1,h3);
Vertex v = t0.cross(t1);
2000/4/21 (HEP初心者の為の)C++入門 50
配列
• 測定点がたくさんあった場合
m0(0.1),m1(0.3),m2(0.2),m3(0.4),,,
ではやり切れない
Hit m[12];
で、12個のHitオブジェクトを一度に作ることが出来る
• 引数無しのデフォールトコンストラクターが12回呼ばれる
• Baseは0である(m[0]が最初のエレメント、 m[11]が
最後のエレメント)
• スコープを外れた場合にはすべての要素が消滅する
2000/4/21 (HEP初心者の為の)C++入門 51
デフォールトコンストラクター
• 定義しなければ、引数無しの、何もしないコンストラクターがコンパイラによって自動的に生成される
• 良いプログラマーは自分で定義するclass Point {public:
Point() : m_x(0), m_y(0) {}…
private:double m_x;
double m_y;};
2000/4/21 (HEP初心者の為の)C++入門 52
変数と記憶領域
• グローバル変数(関数の外側で定義された変数)
• ローカル変数(スコープの中だけでしか使えない)
• 動的に作られる変数
• static変数
– グローバルなstatic変数
– ローカルなstatic変数
– クラスのstaticメンバー
• メモリ管理
2000/4/21 (HEP初心者の為の)C++入門 53
ポインタとレファレンス
• 変数のアドレスを(変数として)格納したり、受け渡しする
int i(343),j(424);
int *ip(&i);
std::cout << i << “ “ << *ip << std::endl;
• 変数のレファレンスを(変数として)格納したり、受け渡しする
int &ir(i);
std::cout << i << “ “ << ir << std::endl;
ip = &j; // OK
ir = j; // not OK
2000/4/21 (HEP初心者の為の)C++入門 54
newとdelete
• 動的に変数や配列(記憶領域)を作るvoid read_points(void) {int npoint;
std::cin >> npoint;Point *p = new Point[npoint];
for(int i=0;i<npoint;++i)std::cin >> p[i];
…delete [] p;
}
• []付きと[]無しの場合を正しく使い分ける事
2000/4/21 (HEP初心者の為の)C++入門 55
for文
for(式1; 式2; 式3) 文
� 式1、式2、式3の何れが空でも良い
� まず式1が一回だけ実行される
� 式2を実行する
� 式2が偽ならばそれでおわり
� 文を実行する
� 式3を実行する
� 式2の実行に戻る
2000/4/21 (HEP初心者の為の)C++入門 56
++i
• C以来の伝統的な略記法の一つ
• ++は演算子である(increment operator)• ++iは、iの値を使用する前に「1」だけ増やす
• i++は、iの値を使用した後に「1」だけ増やす int i(4); int j(++i), k(i++);
で、i, j, kはそれぞれいくつか?
• C++は本当は++Cと呼ばれるべきではなかったか???
• クラスにもこれらの演算子を定義する事が出来る
2000/4/21 (HEP初心者の為の)C++入門 57
istream
• 標準入力(ターミナル等からプログラムへ、値を入力する)標準出力同様、おまじないと思ってそのまま使う
• この関数はfriend関数として宣言しなければ、Pointクラスのデータメンバーに書き込めない。friendには、通常、他の人に見せない“物”も見せてしまう
std::istream &operator>>(std::istream &s,Point &x) {
s >> x.x >> x.y;return s;
}
2000/4/21 (HEP初心者の為の)C++入門 58
bool型
• C++の本でbool型について書かれていなければ、その本は古い本なので買わない方がよい
• C、或いは昔のC++では真(true)偽(false)は整数型に直してから、その値が0なら偽、0以外なら真と定義されていた。新しくbool型がビルトインタイプとして加えられた
• 関係演算子で結ばれた二つの式を評価するとbool型になる(例えばa==bでaとbが等しければtrue)
• ポインタ、整数、浮動小数点数はbool型に暗黙的に変換される
2000/4/21 (HEP初心者の為の)C++入門 59
関数、演算子のオーバーロード
• 色々の型のオブジェクトに対して、同じ機能を持つ関数、演算子がある時、それらを同じ名前の関数、演算子で定義することをオーバーロード(overload)する、という
• 例えば今までみた中ではstd::ostream &operator<<(std::ostream &s,
const Point &x);
が良い例である
• 上手に使えばわかりやすいプログラムが書ける
2000/4/21 (HEP初心者の為の)C++入門 60
定数
• コンパイル時に値が決まっていて、永久にその値が変わらない変数は定数として定義する
• 整数型の場合は、配列等のサイズを指定したりするのに使っても良い
• 説明すると長くなるが、#defineを使うよりは、型を保っているし、ずっとこちらのほうが良いので、こちらを使うようにint max_wires(384);Hit allwirehits[max_wires]; //Not OKconst int max_layers(50);Hit allhits[max_layers]; //OK
2000/4/21 (HEP初心者の為の)C++入門 61
文字列
• 色々流儀はあると思うが、これからは標準テンプレートライブラリのstd::string str(“Hello World”);
std::cout << str << std::endl;
…
を使うのが良い
• 文字列の操作の仕方などの詳しい使い方は本を読んでください
2000/4/21 (HEP初心者の為の)C++入門 62
CLHEP
• 1992年頃、HEPで共通に使えるクラスライブラリを作ろう、という事で始めた
• もう直ぐバージョン2がでる(私がサボっているのが遅れている理由の一つである)
• 今でも使えるのはMatrix, Vector, Random, Geometryの各サブディレクトリにはいっているクラスである。その他List, String等はSTLに既に対応する物があるのでそちらを使うようにするのが良い
• ソースコードは公開されているが、Belleで使っているものはかなり古いバージョンのものである
2000/4/21 (HEP初心者の為の)C++入門 63
テンプレート
• テンプレートを使用することによって任意の型に対して同じプログラムを使う事が出来る。すなわち型をパラメタとして一般的なコードを書く事ができる。例えばmax(a,b)という関数は引数a,bの型に寄らず、aとbの大小関係さえ定義されていれば同じコードが適用される。即ちtemplate<class T>T max(T a,T b){return a>b?a:b;
}
とすれば、すべての型に対して使用できる
2000/4/21 (HEP初心者の為の)C++入門 64
STL
• テンプレートを極限まで屈指して様々な一般的なコンテナタイプ(vector, list等)を定義している
• なかなか判りづらい
• ほぼ完璧なimplementationがようやく使えるよう
になってきた
• 速度が遅いのではないか?
• BELLEでもよく使うので後の講義を聞いてよく勉強してください
2000/4/21 (HEP初心者の為の)C++入門 65
プリプロセッサ
• 最後にソースコードに出てくる、プリプロセッサに対する指示子について、
• #include (必要最小限にする事)
• #define (あまり多用しない事)
• #if … #else … #endif• #ifdef, #ifndef(代わりに#if defined()を使う)
• #(パウンドサイン)は必ず行頭に