目次
C++不勉強だ… Cocos2d-x
が最低限使える程度に勉強しただけだからなぁ。。
引数が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; // コンパイルエラー
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
に頼った実装は設計に問題がある場合がほとんどなので - との判断のらしい。