Google C++スタイルガイドを読んで知らないことを調べたメモ


引数が1つのコンストラクタには explicit キーワード

以下のようなクラスがあるとすると…

class A {
 public:
  A(int integer) {
    printf("%d \n", integer);
  }

  A(float number, float mult = 100.0f) {
    printf("%f \n", number * mult);
  }
};
class B {
public:
  explicit B(int integer) {
    printf("%d \n", integer);
  }

  explicit B(float number, float mult = 100.0f) {
    printf("%f \n", number * mult);
  }
};

このようになる。

  // 引数を一つだけ取るコンストラクタを
  // 変換コンストラクタ(converting constructor) と呼び
  // 以下のような形の場合に暗黙的にコンストラクタが使用される

  A a1 = 1; // 1 と表示される
  A a2 = 1.0f; // 100.000000 と表示される
  // explicit 修飾子をつけると
  // 暗黙的なコンストラクタの呼び出しを禁止できる

  B b1 = 1; // コンパイルエラー
  B b2 = 1.0f; // コンパイルエラー

引数1個のコンストラクタの暗黙呼び出しとexplicit

functor ってなんだ?

()演算子をオーバーロードしたオブジェクト

参考 : C++編(標準ライブラリ) 第15章 関数オブジェクト(ファンクタ)の基礎

traits ってなんだ?

template<class T>
struct hoge_traits {};

template<>
struct hoge_traits<int> {
  typedef  int  traits_type;
  static int func() {return 123;};
};

template<class T>
class Hoge {
 public:
  typedef typename hoge_traits<T>::traits_type traits_type;
  traits_type func() {return hoge_traits<T>::func();};
};
  printf("%d", (new Hoge<int>)->func()); // 123 と出力される

※typename 付けないと hoge_traits::traits_type がコンパイルエラーとなる。

typenameの意味はC++ Labyrinthを読む。

friend class

class S {
 private:
  static int number;
};

class B : public S {
  friend class A;

 private:
  static int number;
};

class A {
  void method() {
    B::number = 100; // アクセス可能!
    B::S::number = 100; // コンパイルエラー
  }
};

friend function

class X {
  friend void friendFunc();
 private:
  static int number;
};

void friendFunc() {
  X::number = 100; // アクセス可能
};

mutable キーワード

この修飾子がついた変数には const の制限を無視してアクセス可能。

class X {
public:
  mutable int number = 0;
  void method() const {
    number++; // エラーにならない
  }
};

Googleのスタイルガイドにあるように mutableはマルチスレッドではスレッドセーフになるよう注意しなければならないし、constメンバ関数は外部から見て const な動作となるようにしなければならない。

ミューテータってなんぞや。

オブジェクトの状態を変更するメソッド。セッターもミューテータに含まれる。イミュータブルなオブジェクトにはミューテータが存在しない…みたいな感じで使用される用語らしい。

intptr_t

ポインタのサイズを表現するための型。
sizeof(void *) == sizeof(int) の結果は環境によって変わるよ。

キャスト

C言語のキャストは使わず、C++の4つのキャスト方法を利用すること

  • static_cast : ビット変換が必要なキャストに使用する。明示的にアップキャストしたい場合にも使用出来る。
  • reinterpret_cast : 安全ではないキャストに使用する。ビットの変換は行われない。
  • dynamic_cast : 型をチェックした上でダウンキャストを行う。アップキャストにも使えるけどそもそもアップキャストは安全なので無意味。これはGoogleのスタイルガイドでは非推奨。
  • const_cast : 非推奨ではないけど、これを使うくらいなら mutableキーワード を使いましょう。
  const char *pszText = "hoge";

  // C cast は何でもあり
  const string *text1 = (string *)pszText;

  // static_cast : コンパイル時にキャストが問題ないかどうか評価してくれる
  const string *text2 = static_cast<const string *>(pszText); // コンパイルエラー

  // reinterpret_cast : C cast とほぼ同じだけど…constは外せない
  const string *text3 = reinterpret_cast<const string *>(pszText);
  const string *text4 = reinterpret_cast<string *>(pszText); // コンパイルエラー

  // const_cast : const や volatile を外す
  char *text5 = const_cast<char *>(pszText);

  // dynamic_cast : 動的にチェックする
  class I { public: virtual ~I(){} };
  class A : public I { public: A(){}; };
  class B : public I { public: B(){}; };
  I *i = new A();
  B *b = dynamic_cast<B *>(i);
  puts(b ? "b" : "null"); // null

  try
  {
    // 参照のキャストに失敗するとbad_cast例外が送出
    B &bRef = dynamic_cast<B &>(*i);
  }
  catch (std::bad_cast e)
  {
    std::cout << e.what() << std::endl;
  }

RTTI と dynamic_cast

RTTIが有効なときには typeid演算子やbefore関数, name関数 が利用可能となる。あと dynamic_cast とかも

GoogleのスタイルガイドによればRTTIはユニットテストだけに利用しろ!って書いてある。RTTIに頼った実装は設計に問題がある場合がほとんどなので – との判断のらしい。

  1. コメントはまだありません。

  1. トラックバックはまだありません。

*


Advertisement