第二章 クラスの概要

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

class-name(param-list); //コンストラクタ
~class-name(); //デストラクタ

それぞれオブジェクトが作られたとき、破棄されるときに呼び出される。コンストラクタでmallocした変数を、デストラクタでfreeすれば幸せになれるみたい。
途中の例題で出てきたctimeのclock()の返値が何時も0になる。謎。

継承

class derived-class-name : access-specifier base-class-name{
....
}

access-specifierで指定された(例題だとpublic)属性の要素が子クラスから見えるらしい。

クラス、構造体、共用体の関連

  • 構造体

クラスとの違いが、デフォルトpublicか、privateかだけ?
だとしたら存在意義がよく分からない。

  • 共用体

共用体がメンバ関数を持つ必要が分からない……。共用体を要素に持つクラスを作れば良いんじゃないかと思ってしまう。
同じメモリ位置を共有するのは多分メンバ変数だけ。
例題のdouble値に含まれるバイナリビットパターンをバイト単位で表示するプログラム。最初見たときよく分からなかったのでメモ。

union bits{
    bits(double n);
    void show_bits();
    double d;
    unsigned char c[sizeof(double)];
};

bits::bits(double n){
    d = n;
}

void bits::show_bits(){
    int i,j;

    for(j = sizeof(double)-1; j>= 0 ; j--){
        cout << "バイト単位のビットパターン" << j << ":";
        for(i = 128; i; i >>= 1)
            if(i & c[j]) cout << "1";
            else cout << "0";
        cout << "\n";
    }
}

unsined char は1byteなので、doubleをunsigned charの配列として見ることで、バイト単位でアクセスすることが出来る。複数の型が同じメモリ位置を参照する共用体の特徴を使っている。
各バイトのビットパターンを見る方法。
i = 128は二進数で10000000。i >>= 1は1bitずつ右にシフトするのでfor文を通じてiは

10000000
01000000
00100000
.....

というふうに変わっていく。c[j]とそれぞれの論理和をとることで、各桁のビットが1か0かがわかる。c[j]が10101111だとすると、10000000との論理和は10000000 != 0という感じで8桁目が1であることが分かる。以下同様に8桁全部を見る。

練習問題2.5.2

共用体クラスを使って、short intの上位バイトと下位バイトを入れ替える。

union swap_byte{
    swap_byte(short int i);
    void swap();

    short int integer;
    unsigned char c[2];
};

swap_byte::swap_byte(short int i){
    integer = i;
}

void swap_byte::swap(){
    unsigned char a;
    c[0] = a;
    c[0] = c[1];
    c[1] = a;
}

インライン関数

関数定義の前にinlineを付けると、関数がインライン展開され関数呼び出しのオーバーヘッドが無くなって早くなる。inlineは要求であり、コンパイラは無視する可能性がある。
基本的にはオーバーヘッドが無視できない小さな処理をインライン関数にする。

自動インライン化

クラス定義の中で関数の処理を書くと、自動でインライン化される。
一般的な使用方法はコンストラクタやデストラクタの定義を暮らす定義の中で行う。
性能にはあまり影響が無くても、短い関数はクラス定義ないで書くことがある。