Aritalab:Lecture/Programming/Cpp

From Metabolomics.JP
< Aritalab:Lecture | Programming(Difference between revisions)
Jump to: navigation, search
m
m
Line 55: Line 55:
 
これを用意しておくと、<tt>make main</tt> や <tt>make clean</tt>と打つだけでコンパイルや片づけができます。
 
これを用意しておくと、<tt>make main</tt> や <tt>make clean</tt>と打つだけでコンパイルや片づけができます。
 
--->
 
--->
 +
===ファイルの入出力===
 +
C&#43;&#43;では入出力にオペレータ<tt><<, >></tt>を使います。
 
;与えられたファイルを全て結合して表示する cat.cpp
 
;与えられたファイルを全て結合して表示する cat.cpp
 
<pre>
 
<pre>

Revision as of 17:07, 7 October 2010

Wiki Top Up one level レポートの書き方 Arita Laboratory

Contents

C++プログラミング

C++はC言語の完全な上位互換ですが、オブジェクト指向型という点でC言語とは全く違うプログラミング思想に基づいています。簡単に言うと、JavaはC++の利点を活かすように開発された言語です。

マクロ, inlineの利用

C言語でマクロが果たしていた役割を、C++ではinline関数を用いて実現できます。 関数定義を

inline int cmp(const char& x, const char& y)
{ if (x < y) return -1; else if (x > y) return 1; else return 0; }

と書いておくと、cmp(x,y)という呼び出しはコンパイル時に全てソース中に展開されます。 実行ファイルが大きくなるのは欠点ですが、処理速度を犠牲にせずに可読性が上がります。

ヘッダーファイル

利用する関数の型情報は.h.hhという拡張子を持つヘッダーファイルに記述し、それをプログラムの先頭で読み込みます。一番有名なヘッダーは<stdio.h><iostream>でしょう。

#include <stdio.h>

iostreamも以前は拡張子(.h)を付けてインクルードしていたのですが、標準化の際に付けないことが決まりました。なので以下のように書いてください。

#include <iostream>
using namespace std;

二行目のusing以下は、iostreamで定義される標準入出力 std::cin, std::cout を、std::というネームスペース名無しで利用するために記述します。

ヘッダーファイルはクラスを定義するソースプログラム毎に用意します。ディレクトリ内に.c.cpp等のファイルと混在してくると面倒です。例えばinclというディレクトリを作り、その中にヘッダーを集めておくと便利でしょう。(コンパイル方法は後述。)

各ヘッダーファイルは、プログラム中で複数回読み込むとエラーになります。ヘッダーファイルの先頭に

#ifndef LIST_HH
#define LIST_HH
#include "iterator.hh"
  :
#endif

のように、ifndefのおまじないを入れておきましょう。

ファイルの入出力

C++では入出力にオペレータ<<, >>を使います。

与えられたファイルを全て結合して表示する cat.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

int main(int argc, char *argv[])
  {
    vector<string> lines;
    string line;
    for(int i=1; i < argc; i++) {
      //argv[0]には実行ファイル名が入っている
      ifstream fin;
      fin.open(argv[i], ios::in);
      if(!fin ){// 必ずエラーチェックを入れる
        cout << "Error: cannot open file(" << argv[i] << ")" << endl;
        exit(1);
      }
      while(getline(inf, line))
        lines.push_back(line);
    }
    for(vector<string>::iterator itr=lines.begin();
        itr != lines.end(); ++itr)
      cout << itr->c_str() << endl;
  }

クラス定義

class class名 {
private:
   // 外からアクセスできない変数やメンバー関数
public:
   // 外からアクセス可能な変数やメンバー関数
};

と定義します。C言語における構造体との主な違いはアクセス制限です。 クラス定義の中では、自分自身をthisポインタで参照することができます。

メモリ管理

コンストラクタとデストラクタ

C++のクラス定義では、例えば以下のような記述をします。

class list_node;
typedef list_node* lnode;

class list_node {
private:
  list_node(const list_node&);
  list_node& operator=(const list_node&);
public:
  void* key;
  lnode list_pred;
  lnode list_succ;
  list_node(GenPtr x=0x0) : key(x), list_pred(0), list_succ(0) {}
  ~list_node() {}
};

この中でlist_node(GenPtr x=0x0)とあるのがコンストラクタ、~list_node()がデストラクタで、それぞれクラスのインスタンス生成、消去時に呼び出されます。コンストラクタ内ではクラス変数の初期化、デストラクタ内では必要なくなったポインタのnull化などをしておくと良いでしょう。(後者は無駄に思えるかもしれませんが、バグをなくすのに役立ちます。)

コピーコンストラクタと演算子のオーバーロード

上の例でprivate指定でアクセス制限されているのが、コピーコンストラクタlist_node(const list_node&)と演算子=の定義list_node& operator=(const list_node&)になります。 コピーコンストラクタは、

list_node x = 既に定義されているlist_nodeクラス;

と=をつけて初期化する場合と、関数にクラスを(参照渡しではなく)値渡しするときに実行されます。 また、演算子=のほうは、

list_node x,y;
x = y = 既に定義されているlist_nodeクラス;

と書かれたときに実行されます。上の例では、list_nodeクラスがユーザに無闇にコピーされることを防ぐためにprivate指定にしています。

new と delete

Cにおけるmalloc/freeと、new/deleteは同じではありません。 クラスのnew/deleteでは、コンストラクタとデストラクタが呼ばれることに注意しましょう。 基本データ型のnew/deleteは、基本的にmalloc/freeと同じですが、void*しか返さないmallocに比較して型キャストの必要がありません。

ですから、C++らしいプログラムを心がけるには、常にnew/deleteを使うと良いでしょう。

働きの全く同じ二つの例
char** cArray = new char*[10];
delete[] cArray;

char** cArray2 = (char**) malloc(sizeof(char*)*10);
free(cArray2);

Garbage Collection

Javaとの最大の違いは、メモリ管理を自分で行う点です。これは単に「遅れている」という訳ではなく、実時間プログラミングのようなGarbage collector(GC)が致命的となる場合でも用いられる「汎用性」と捉えましょう。C++の人が GC を使う際には boost::shared_ptr 等を使うのが普通だそうです。

Personal tools
Namespaces

Variants
Actions
Navigation
metabolites
Toolbox