EffectiveC++改訂2版 第17項〜第21項

17項

AcceleratedC++でも何度も注意されていた「自己代入」のチェック。ほとんどの場合、this と &rhs の比較で判定すれば良い。
エイリアシングの可能性を考慮しなければいけない理由

  • 効率:代入は非常にコストがかかる操作になる場合がある
  • 安全:間違いを犯さないようにする。代入時に古いリソースを破棄するが、新しいリソース割り当て際に古いリソースが必要なことがある。

18項

完全でしかも最小限のクラスインタフェース
  • クライアントが普通やりたいと思うようなことは、何でもできる
  • 関数の数が可能な限り切り詰められていて、関数同士で機能がオーバーラップしていない
関数が一杯詰まったインタフェースの技術的な欠点
  • インタフェースに含まれる関数の数が多ければ多いほど、クライアントにとって理解し難いものになる
  • 大きいインタフェースは保守が難しい
  • 必要以上に長いクラス定義、プロジェクトの存続期間を通じて、コンパイル時間に大きなペナルティを与えかねない。

要するにインタフェースには、只で関数を追加しようと思っても結局コストがかかったしまうのだから、その関数を加えることによって得られる利便が、その使いによって加わる複雑さや、それによって損なわれる理解の容易さや保守性、コンパイル速度などといったコストに十分見合うものかどうかを、慎重に考慮しなければならない。

19項

メンバ関数と非メンバ関数のもっとも大きな違い

メンバ関数は仮想関数にすることができるが、非メンバ関数はできない。
だから動的に結合する必要のある関数があれば、それには仮想関数を使わなければならず、仮想関数は、何かのクラスのメンバでなければならない

暗黙の型変換
  • explicit なコンストラクタは、暗黙の方変換に使えない
  • コンパイラが暗黙の方変換を行うのは、パラメータリストに書かれているパラメータだけであり、メンバ関数を呼び出したオブジェクト、すなわち *this に相当するオブジェクトに対しては、決して暗黙の型変換を行わない
  • operator*() をメンバ関数とした場合に成功する場合と失敗する場合
    • 成功:result = oneHalf * 2;
    • 失敗:result = 2 * oneHalf;
  • operator* を非メンバ関数にすれば、コンパイラがすべてのパラメータを暗黙のうちに型変換してくれる
メンバ関数と非メンバ関数の選択のまとめ

第20項

これはもう身に付いているので良し。

第21項

const かそうでないかだけが異なるメンバ関数は、多重定義できる。
char& operator[](int pos) { return data[pos]; }
const char& operator[](int pos) const { return data[pos]; }
メンバ関数const であるということ
  • ビット的定数性
    • オブジェクトのデータメンバを変更できない(static データメンバを除く)
    • ポインタを通してデータメンバを変更できてしまう場合がある
  • 概念的定数性
    • constメンバ関数でも呼び出しの対象であるオブジェクトのビットの一部を変更してもかまわない
    • 非static メンバに mutable キーワードをつけるとビット的定数性の制約から逃れられる
    • const_cast() を使用する。安全な場合のみ

mutable は知らなかった。というわけで使ってみる。

#include <iostream>

class TestClass {
public:
    TestClass(int val1 = 0, int val2 = 10): data1(val1), data2(val2) { }
    void func() const {
        ++data1;
        TestClass *p = const_cast<TestClass *>(this);
        ++(p->data2);
    }
    void show() {
        std::cout << "data1 = " << data1 << ", data2 = " << data2 << std::endl;
    }
private:
    mutable int data1;
    int data2;
};

int main()
{
    TestClass   x;
    x.show();
    x.func();
    x.show();
}

実行結果

data1 = 0, data2 = 10
data1 = 1, data2 = 11
  • -