キャストが完全に必要な状況が存在するかどうか疑問に思っています。
ここでは、基本型ではなく、クラス間のキャストについて話しています。
static_cast
キャスト (またはのような C++ スタイルdynamic_cast
、または単純な C スタイルのキャスト) はコードの匂いですか? 役に立つ場合もあるが、避けることもできると思う。キャストは OOP ルールに違反しますか?
キャストが完全に必要な状況が存在するかどうか疑問に思っています。
ここでは、基本型ではなく、クラス間のキャストについて話しています。
static_cast
キャスト (またはのような C++ スタイルdynamic_cast
、または単純な C スタイルのキャスト) はコードの匂いですか? 役に立つ場合もあるが、避けることもできると思う。キャストは OOP ルールに違反しますか?
特にありません。キャストは可能な限り避けるべきですが、最も基本的なレベルでは、タイプ セーフの領域外に存在する C++ の領域があり、キャストが必要です。dynamic_cast
は特別な例外です。具体的には、ソリッドな OOP 設計でも必要になる場合があります。
「それは不完全だ」と「OMGWTF、YU SO DUMB」があります。キャストは不完全です。
コードのにおいによって、コードレビューでフラグを立てる必要があることを意味する場合、それらはコードのにおいです。それらがコードに表示されてはならないという意味であれば、いいえ、キャストにはいくつかの優れた使用法があります。
興味深い例 (型の消去は常に興味深いと思います) については、格納された値から安全に読み取るために が必要なboost::any
場所の実装を見てください(型を推測する必要があり、制限されている s とは異なります)。dynamic_cast
union
スケッチ:
struct any_base {
virtual ~any_base() {}
};
template <typename T>
struct any_data : any_base {
T value;
any_data( T const & value ) : value(value) {}
};
struct any {
any_base * data;
any() : data() {}
~any() { delete data; }
template <typename T>
any( T const & v ) : data( new any_data<T>(v) {}
}
template <typename T>
T any_cast( any const & a ) {
any_base<T> * p = dynamic_cast< any_base<T>* >( a.data );
if ( !p ) throw invalid_cast();
return *p;
}
キャスティングが適切な選択である合理的なケースがあるため、適切な設計によってキャスティングを完全に回避することはできないと言えます。プロキシは非常に便利で、通常は遅延評価を行う次のような暗黙的または明示的なキャストに依存しています。
template <class fn_t, class result_t>
class lazy_t {
fn_t fn_;
public:
lazy_t(fn_t fn) : fn_ (fn) { }
operator result_t () { return fn_(); }
};
この場合、コンパイラは暗黙的なキャストを使用して、指定された関数の遅延評価を実行できます。変換演算子は、クラスのパブリック インターフェイスの一部であると考えます。
複数のディスパッチを実装するなどの特定のケースでは、dynamic_cast<> も必要です。詳細については、 http://en.wikipedia.org/wiki/Multiple_dispatchを参照してください。
プログラムで複雑なコードが必要になる場合があります。言語の単純、基本、または「クリーン」な要素に常に固執できるとは限りません。
典型的な例は I/O です: これは、キャストする数少ない唯一の理由の 1 つであり、C++ で唯一の正当なポインター型の 1 つも使用します: char *
:
uint32_t n;
infile.read(reinterpret_cast<char *>(&n), sizeof n);
n *= 2;
outfile.write(reinterpret_cast<const char *>)(&n), sizeof n);
他の「I/O に似た」操作には、暗号化やエンコード変換など、同様のパターンが必要です。
(C++ の他の正当なポインタはvoid *
、割り当てのコンテキストで使用される場合ですが、キャストする必要はありません。メモリ ポインタをオブジェクト ポインタに「変換」する C++ の方法は、構築: void * addr = get_memory();
, then を使用しT * p = new (addr) T;
ます。)