C キャスト 新しいページはコチラ

提供: yonewiki
移動: 案内, 検索
(キャスト)
 
1行: 1行:
 +
[[C PlusPlus#Cにもあった技術|C++]]へ戻る
 +
 +
 
※このページではC言語にも存在していたという意味で記事タイトルが<nowiki>C -キャスト</nowiki>になっていますが、<br />
 
※このページではC言語にも存在していたという意味で記事タイトルが<nowiki>C -キャスト</nowiki>になっていますが、<br />
 
[[C PlusPlus|C++]]でも同様です。[[C PlusPlus|C++]]だけの機能がある場合は明記します。<br />
 
[[C PlusPlus|C++]]でも同様です。[[C PlusPlus|C++]]だけの機能がある場合は明記します。<br />
 
<br />
 
<br />
 
== '''キャスト''' ==
 
== '''キャスト''' ==
型変換/型変更/const外しを行うことをキャストと呼びます。const外しは少し特殊な表現ですが、constと同時に定義される型の変更と思えば、型に関する処理という意味では同じです。キャストcastには割り当てるという意味がありますので、新しい型を割り当てる処理と考えれば、それぞれの変換の総称になっていることも納得できるでしょうか。
+
 
 +
型変換/型変更/const外しor戻しを行うことをキャストと呼びます。const外しは少し特殊な表現ですが、constと同時に定義される型の変更と思えば、型に関する処理という意味では同じです。キャストcastには割り当てるという意味がありますので、新しい型を割り当てる処理と考えれば、それぞれの変換の総称になっていることも納得できるでしょうか。
  
  
一般的にキャストは危険な操作です。メモリの使い方を間違えないように型宣言をした変数なのに、それをなかったことのようにしたいというわけですから。もっと緩やかな意味で型を定義したつもりがガチガチすぎるので、変換してコンパイラエラーをかいくぐるという使い方になると思うので、プログラムする人があえて、その危険の潜む変換を指示するという処理になります。大丈夫な変換だとプログラムがお墨付きをだすようなことです。
+
一般的にキャストは危険な操作です。メモリの使い方を間違えないように型宣言をした変数なのに、それをなかったことのようにしたいというわけですから。もっと緩やかな意味で型を定義したつもりがガチガチすぎるので、変換してコンパイラエラーをかいくぐるという使い方になると思うので、プログラムする人があえて、その危険の潜む変換を指示するという処理になります。大丈夫な変換だとプログラムする人がお墨付きをだすようなことです。
  
  
56行: 60行:
 
  pintLength = (int*)puintLength;
 
  pintLength = (int*)puintLength;
  
 
+
のようにして型変更をします。今回の例では問題にならない変更になっていますが、まったく関係の無い型どうしでも変更できてしまいます。非常に危険です。引数に仮の型で受け取った関数でどの型の無いようになっているかが判明するような関数では、この仮の型から無理やり変更をする必要が生じる場合があるのかもしれません。変数の中におさめられている中身が変更に対応できるとわかっている場合に有効です。
 
そしてconst付きのint ポインタ変数にnLimitのアドレスを紐づけて、pconstnLimitからは中身を変更できないようにした場合
 
そしてconst付きのint ポインタ変数にnLimitのアドレスを紐づけて、pconstnLimitからは中身を変更できないようにした場合
  
63行: 67行:
 
  pconstnLimit = &nLimit;
 
  pconstnLimit = &nLimit;
  
※上記のconst付きのポインタはポインタのアドレスは変更できるconstで、アドレスは何度でも入れ替えることができます。アドレスが指し示す中身を変更できないようにするものです。
+
※上記のconst付きのポインタはポインタのアドレスは変更できるconstで、アドレスは何度でも入れ替えることができます。アドレスが指し示す中身を変更できないようにするものです。アドレス自体を変更させないconstにする場合は、int* const pconstnLimit = &nLimit; のように *の後ろにconstを付与します。そうすると自分の場合は変数名も constpnLimit としてポインタが定数になったようなプレフィックスを変数名につけたりします。このプレフィックスの法則は面倒なので、長続きしたためしがありませんが(汗。const int* const pconstnLimit = …;とすると中身もアドレスも変更できなくなります(constpconstnLimitになるか…)。値の中身の変更を禁止するconstは 型名の後ろに書くことができますので、int const * const pconstnLimit = …;とも書けます。どちらにしてもあまり見かけない使い方だとは思います。C++の難しさはこのあたりにあると思う。こうやって書いてもいいという曖昧さ。柔軟さ?
  
 アドレス自体を変更させないconstにする場合は、int* const pconstnLimit = &nLimit; のように *の後ろにconstを付与します。
 
  
 const int* const pconstnLimit = …;とすると中身もアドレスも変更できなくなります。値の中身の変更を禁止するcointは 型名の後ろに書くことができますので、
 
  
 int const * const pconstnLimit = …;とも書けます。どちらにしてもあまり見かけない使い方だとは思います。C++の難しさはこのあたりにあると思う。こうやって書いてもいいという曖昧さ。柔軟さ?
+
*const外しor戻し
 
+
 
+
 
+
 
+
*const外し
+
 
  pnLimit = (int*)pconstnLimit;
 
  pnLimit = (int*)pconstnLimit;
  
  
のようにすることができます。キャストは型の大きさに違いがなく、型名が変換できるものや、変更できるものに使いますが、もっと大きなサイズの変数となる構造体やクラスのキャストはキャストできるできないの判定に複雑さが増します。
+
のようにすることができます。const_castは最大の違反ですので、これを使うという事はプログラム自体に問題があるので修正することが正しい道なはずですが、引数の変数や文字列の中身を何も変更しない関数なのに何かの手違いで、const以外の変数を引数に指定している変更するだけの権限や時間が無い既存の関数が与えられた場合に使うことになります。const外しをしないとコンパイルエラーになるのを一時的に回避する手段だと考えていいでしょう。他にもconstに似た使い方をする最適化のためのオプションvolatile外し(こちらはあまり知られていない)としても動作します。キャストは型の大きさに違いがなく、型名が変換できるものや、変更できるものに使いますが、もっと大きなサイズの変数となる構造体やクラスのキャストはキャストできるできないの判定に複雑さが増します。
  
  
このような難しい型の変換もあるという背景とキャストに対する仕組みの改善からC++では新しいcastの指定が4つ増えました。
+
このような難しい型の変換もあるという背景とキャストに対する仕組みの改善からC++では新しいcastの指定が4つ増えました。変換を有効に利用することも使い手しだいですが、危険を冒していることに気付かなければキャスト処理は崩壊を招きます。よく使うキャスト、苦し紛れのキャスト、とんでもないキャスト、間違ったキャスト。いろいろできます。最終的に正しく動作するなら、それでもいいってことになります。でも治せるものは早くなおしなよっていう感じですね。
  
  
 
*static_cast     変換
 
*static_cast     変換
 
*reinterpret_cast   変更  
 
*reinterpret_cast   変更  
*const_cast     const外し
+
*const_cast     const外しor戻し
 
*dynamic_cast
 
*dynamic_cast
  
93行: 90行:
  
 
*変換
 
*変換
  (int)uintLength
+
  intLength = (int)uintLength;
  '''static_cast<int>'''uintLength
+
  intLength = '''static_cast<int>'''uintLength
 
*変更
 
*変更
 
  pintLength = (int*)puintLength;
 
  pintLength = (int*)puintLength;
 
  pintLength = '''reinterpret_cast<int*>'''puintLength;
 
  pintLength = '''reinterpret_cast<int*>'''puintLength;
*const外し
+
*const外しor戻し
 
  pnLimit = (int*)pconstnLimit;
 
  pnLimit = (int*)pconstnLimit;
 
  pnLimit = '''const_cast<int*>'''pconstnLimit;
 
  pnLimit = '''const_cast<int*>'''pconstnLimit;
 +
pconstnLimit = '''const_cast<const int*>'''pnLimit;
 +
 +
 +
dynamic_castはクラスの継承関係でcast可能なものと不可能なものがあり、親(基底クラス)から子(派生クラス)へのクラス名変換はキャスト動作はほぼ不可能で、その逆はキャストできるケースがあります。これは親より子の方が肉付けされる分だけ型は大きくなっているはずだからです。その逆の変換であれば、子クラスだけの機能やメンバ変数がそぎ落とされるものの変換が可能になります。このような変換の可否を実行時に判断してくれるのが、dynamic_castです。使い方は上の3つと同じです。クロスキャスト(親子の関係が無いクラス同志のキャスト)やダウンキャスト(そのままは使えない抽象クラスの変数で派生クラスにキャストする親から子をのキャスト)と呼ばれるキャストも実行時に検索します。キャストするクラスが仮想関数を保持している必要があるという制限もあります。const外しor戻しはできません。
  
  
dynamic_castはクラスの継承関係でcast可能なものと不可能なものがあり、親(基底クラス)から子(派生クラス)へのクラス名変換はキャスト動作はほぼ不可能で、その逆はキャストできるケースがあります。これは親より子の方が肉付けされる分だけ型は大きくなっているはずだからです。その逆の変換であれば、子クラスだけの機能やメンバ変数がそぎ落とされるものの変換が可能になります。このような変換の可否を実行時に判断してくれるのが、dynamic_castです。使い方は上の3つと同じです。クロスキャスト(親子の関係が無いクラス同志のキャスト)やダウンキャスト(そのままは使えない抽象クラスの変数で派生クラスにキャストする親から子をへのキャスト)と呼ばれるキャストも実行時に検索します。
+
失敗すると例外をスローします。詳しいサンプルはまた後日。まずはクラス関連の記事を全部書いてから、自分もここに戻ってきて記事を書きたいと思います。たぶん、dynamic_castの記事ができるのは、数年後になりそうですね。ごめんなさい。言葉で、ダイナミックキャストのイメージだけでも伝われば幸い。詳しいことは、他のSiteで調べれば、よりイメージが具体化されるでしょう。どういうときに明示しなければエラーになるのか?どういう構造なら変換・変更・const外しができるのか?あいまいなままの説明になっているので、変換・変更・const外しor戻しの具体的なサンプルもあったほうがいいでしょうね。
  
  
失敗すると例外をスローします。詳しいサンプルはまた後日。まずはクラス関連の記事を全部書いてから、自分もここに戻ってきて記事を書きたいと思います。たぶん、dynamic_castの記事ができるのは、数年後になりそうですね。ごめんなさい。言葉で、ダイナミックキャストのイメージだけでも伝われば幸い。詳しいことは、他のSiteで調べれば、よりイメージが具体化されるでしょう。どういうときに明示しなければエラーになるのか?どういう構造なら変換・変更・const外しができるのか?あいまいなままの説明になっているので、変換・変更・const外しの具体的なサンプルもあったほうがいいでしょうね。
+
[[C PlusPlus#Cにもあった技術|C++]]へ戻る

2017年5月29日 (月) 00:00時点における最新版



個人用ツール
名前空間

変種
操作
案内
ツールボックス