ちょっとだけ C++


C++とは

C++は、C言語の後継として、Bjarne Stroustrup氏が設計した言語である。 基本的にC言語と互換性を保ったまま、新しい仕様を追加した ものであり、当初はC++のソーステキストをCに変換し、それを Cコンパイラでコンパイルするという「トランスレータ」実装もあった。

非常に多くの機能がある巨大な言語だが、オブジェクト指向言語として クラスの機能を付け加えたのが最大の変更と言えよう。 (最初期はC with classesと呼ばれていた)

とても全体は説明しきれないが、わかりやすいところから簡単に紹介していく。

Hello World

いわゆるhello worldはこんな感じ。

#include <iostream>

int main()
{
    std::cout << "Hello world" << std::endl;
}

hello.cpp

ソースファイルの拡張子は.cpp, .cc, .cxxなどいろいろある。 コンパイルは、c++ hello.cpp。

printfの代わりに「cout << 変数名」を使う。endlは改行。 「#include <iostream>」はcoutを使うのに必要。

printfを使うことも可能で、その場合は「#include <cstdio>」とする。

「std::」は、「stdという名前空間に属する」という意味。C++は巨大なので、 名前の衝突を避けるためにいろいろな名前を「名前空間」に分類する機能がある。 いちいち付けるのが面倒ならば、

using namespace std;
と書くと、グローバルな名前空間にstd内の名前を引っ張り出すことも出来る。

クラス

クラスの概念はなかなか分かりにくいが、オブジェクト指向の考え方を 実現するためのもので、「データ構造とそれを操作するための関数群を 一体にしたもの」とでも言えばいいだろうか。
#include <iostream>

class test {
    private:

    int age;
    int height;

    public:

    void setage(int x) {
        age = x;
    }

    void setheight(int x) {
        height = x;
    }

    void print() {
        std::cout << "(" << age << "," << height << ")" << std::endl;
    }
};

int main()
{
    test t;

    t.setage(20);
    t.setheight(170);

    t.print();
}

class.cpp

C++では、構造体の機能を拡張してクラスを実現している。 上の例は、

struct test {
    int age;
    int height;
};
という構造体の宣言に、あれこれ加わったものと見てほしい。 つまり、これは構造体testの宣言と、その構造体を操作する関数 setage, setheight, printを一まとめにしたもの。

あえてC言語で同じ動作をするプログラムを書けば、

#include <stdio.h>

struct test {
    int age;
    int height;
};

void test_setage(struct test* s, int x) {
    s->age = x;
}

void test_setheight(struct test* s, int x) {
    s->height = x;
}

void test_print(struct test* s) {
    printf("(%d,%d)\n", s->age, s->height);
}

int main()
{
    struct test t;

    test_setage(&t, 20);
    test_setheight(&t, 170);

    test_print(&t);
}

class2.c

のようになるだろうか。 mainからの呼び出し方から、Cでの「主体は関数」と、 C++での、「主体はデータで関数はそのデータに付随する」という 考え方の違いが感じられるだろうか。 一つのプログラムの中で何種類もの構造体(クラス)を使うようになると、 Cだとどの関数がどの構造体を操作するものか混乱しがちだが、 C++だとすっきり書けるようになる。

private:, public:もC++の機能で、private指定の部分は外部から直接 アクセス出来なくなる。これにより、メンバ変数はpublic指定された 関数(メンバ関数)経由でしか操作されないので、プログラムの安全性が増す。

コンストラクタ、デストラクタなど、クラス関連の重要な知識は まだたくさんあるが、とりあえずここまで。 既存のクラスを一部変更したり機能を追加したりして新しいクラスを作る、 「継承」の概念も重要。

関数のオーバーロード

引数の型の異なる同名の関数を作成できる。 言い換えれば、同じ関数名でも引数が違えばそれらは違う関数と認識される。
#include <iostream>

int addtwo(int x, int y)
{
    return x + y;
}

int addtwo(double x, double y)
{
    return x + y;
}

int main()
{
    int a=1, b=2;
    double x=2., y=3.;

    std::cout<< addtwo(a, b) << std::endl;
    std::cout<< addtwo(x, y) << std::endl;
}

overload.cpp

内部で自動的にaddtwo_int_intやaddtwo_double_doubleのような名前に 置き換えられている、と考えれば分かりやすいかも。

参照型

説明が難しいが、自動で適切に「&」や「*」がつく ポインタのようなもの?(多分嘘)。 よくある2つの変数を入れ替える関数だが、次のように書ける。

int swap(int &x, int &y)
{
    int tmp;

    tmp = x;
    x = y;
    y = tmp;
}

int main()
{
    int a=1, b=2;
    swap(a, b);
}

reference.cpp

関数の引数の「int &x」が参照型。 C言語で同じものを書けば、

int swap(int *x, int *y)
{
    int tmp;

    tmp = *x;
    *x = *y;
    *y = tmp;
}

int main()
{
    int a=1, b=2;
    swap(&a, &b);
}

reference2.c

のようになる。通常変数から参照型へコピーするときは自動で 「&」が付き、参照型を使うときは自動で「*」が付くと思えば理解しやすい。

演算子オーバーロード

関数のオーバーロードを更に発展させて、 自分で定義したクラスに対する演算子の機能を定義する。

#include <iostream>

class hoge {
    public:
    int a;

    int operator+(int x) {
        return a + x;
    }
};

class fuga {
    public:
    int a;

    int operator+(int x) {
        return a - x;
    }
};

int main()
{
    hoge p;
    fuga q;

    p.a = 3;
    q.a = 3;

    std::cout << p + 2 << std::endl;
    std::cout << q + 2 << std::endl;
}

operatoroverload.cpp

hogeとfugaでそれぞれ異なるmethod(関数)が呼び出されているのが分かる。

これを応用すると、例えば複素数クラスのようなものを作成し、 複素数型を「あたかも初めから組み込まれていた型であるかのように」 振舞わせることが出来る。

詳細に興味があれば、C++での演算子多重定義を 見て欲しい。

テンプレート

テンプレートとは、簡単に言えば、変数の型を未定にしたまま クラスや関数を定義する機能である。C言語のマクロ機能を発達させたものという 見方も出来る。

その他

コメントは、 の2種類。
ちょっとだけC++ /