ぼく用あれこれまとめ
const型修飾子
最終更新:
bokuyo
-
view
const型修飾子
こんな感じで。
class IUnco { void Unco(int const& num)const { std::cout << num << std::endl; } };
const定数
const int eureka = 16; int const renton = 14;
- 上のeurekaさんの宣言はわりとよく見かけるけど、その下のrentonさんの宣言はマイナーだよね。
- この場合はこれといった違いはない。
constポインタ
const int* Eureka; //これはおっけー int* const Renton; //これはだめ!初期化しろぉー>< int const* Anemone; //これもおっけー
- この場合、2行目のRentonの宣言はコンパイラたんに怒られる。「Renton初期化しろ!」って感じで。
- それぞれの違いは、
const int* | 「const int」のポインタ。つまり、「int型の定数を指すポインタ」っていう意味 …と思ってたけど、そうじゃなくて「読み取り専用ポインタ」って意味。 ポインタで指してる場所は何度でも変更可能。「int型の定数」を指すのではなくて「int型」なら何でも指せる。 「*Eureka」で値を読み取れる。ただし「*Eureka = 156」のようにポインタを通じて代入することはできない。つまり読み取り専用。 |
int* const | 「intのポインタ」をconstに。つまり、「指す場所が変更不可能なint型のポインタ」という意味。 ポインタで指す場所は宣言と同時に定義しないとコンパイラたんに怒られる。 int型の定数を指すのではなく、普通のint型の整数を指せるってこと。 |
int const* | 「int const」へのポインタ。つまり「int型の定数を指すポインタ」 …って考えたいけど実は「読み取り専用のポインタ」。「const int*」とたぶん全部同じ。 ポインタで指してる場所は何度でも変更可能。「*Anemone」で指してる場所の値を読み取れる。 「*Anemone = 156;」のようにポインタを通じて値を変更することはできない。よって読み取り専用。 |
constポインタの位置
int Lynette = 156; int Thurston = 14; const int* Eureka = &Lynette; int* const Renton = &Thurston; Eureka = &Thurston; Renton = &Lynette; //←これはコンパイルエラー
- 上の例では、最後の行でコンパイルエラーをはきます。「int* const」なのに指す場所を変更しようとしたからです。
- C言語の関数の引数でよく見かける「const int*」は、読み取り専用ポインタとして使うときくらいしか出番がない気がする。
- 使うとしたら、関数の引数に使うときくらい。でもC++だと参照とかあるし、使う機会あるかなぁ?
- もし使うとしたら、「int* const」の形かな?
- 宗教的だけども、「int const」と「int* const」の形でconstは使ったほうがいいよ。
- constの適用箇所がわかりやすい、ってのが大きな理由。
- もしCっぽく関数の引数で読み取り専用ポインタとか使うときは、「const int * ptr」の形でいいと思う。
- mutable, volatileについても同様なことが言える。
- 宗教的だけども、「int const」と「int* const」の形でconstは使ったほうがいいよ。
もうひとつ例をあげるなら
typedef int* TINPO; typedef TINPO const TINPOCO;
- このTINPOCOは、「int* const」と同じ意味です。
- 2行目の「TINPO」をそのまま「int*」と置き換えて「typedef int* const TINPOCO;」と書くことも容易にできます。
typedef int* TINPO; typedef const TINPO COTINPO;
- このCOTINPOも、「int* const」と同じ意味です。
- ですが、2行目の「TINPO」をそのまま「int*」と置き換えると「typedef const int* COTINPO;」になります。
- これは、「const int*」という意味になり、置き換えが利かないことがわかります。
- このことから、「int* const」のように「型* const」の形で使うほうがいいことがわかります。
そんなこんなで
const int const eureka = 7; //これはconstは型の前後どっちにつけても一緒だからコンパイルエラー const int* const renton = &eureka; //これはちゃんと前後で意味が変わるからコンパイルエラーにならないお。
constメンバ関数
class Eureka { int seven; public: int GetSeven()const; }; int Eureka::GetSeven()const{ return seven; };
- メンバ関数の後ろに「const」をつけると、constメンバ関数になります。
- constメンバ関数内では、classのメンバ変数に数値を代入したり加えたりすることはできません。
- Read-Onlyになるってこと。Writeはできないの。
- ってことは、読み取り専用の関数を作る場合、constメンバ関数にしたほうが安全だよね。
class Eureka { int seven; public: int GetSeven()const{ seven = 7; //←ここが問題なの!!ねえきいてる? return seven; }; };
これはコンパイラに怒られちゃいます。
error C3490: 'seven' は const オブジェクトを通じてアクセスされているため変更できません
でも、どうしても、GetSeven()の中で「seven=7」を入れたくなるときがありますよね。
そういうときは、「mutable」を使いましょ。
そういうときは、「mutable」を使いましょ。
mutable修飾子
class Eureka { int mutable seven; };
- mutable修飾子をつけるとconstメンバ関数内でも値を入れたり加えたり自由にできるのお兄ちゃん!
- mutableってお金につられてほいほい男を変えていく女の子みたいなイメージ。どうでもいい。
参考文献
C++テンプレート完全ガイド(著:David Vandevoorde, Nicolai M. Josuttis, 訳:津田 義史 )