出力用シフト演算子(<<)のオーバーロード
C++ の標準ライブラリでは cout などにシフト演算子(<<)を使って出力します。
std::cout << "Hello World!!" << std::endl;
これは iostream の上位クラスである ostream のシフト演算子(<<)のオーバーロードで実現されているのですが、これを自分で定義したクラス、構造体、列挙型などに対しても定義しておくと便利です。
これを定義しておくだけで、標準出力(cout), ファイル(ofstream), 文字列(stringstream)などにも自分で作ったクラス等を文字列として出力することが出来ます。
どうやるかというと、例えば点の構造体 Point があったとすると以下のように ostream クラスとシフト演算子(<<)の 2 項演算をオーバーロードします。
std::ostream &operator<<(std::ostream &out, const Point &tgt)
{
out << "(" << tgt.x << "," << tgt.y << ")";
return out;
}
この定義はクラス(構造体)定義の外で行うので、列挙型も定義できます。
ただし、クラスの場合は外なのでゲッターなどを用意しておく必要があります。
さらに以下のようなテンプレート関数を用意しておけば、簡単に文字列に変更できます。
template <typename T_t>
std::string to_str(const T_t &val)
{
std::stringstream ss;
ss << val;
return ss.str();
}
この関数は int 基本型を含めた ostream のシフト演算子(<<)をオーバーロードしているものであれば何でも文字列に変換できます。
to_str(5); // "5"
to_str(Point(2, 3)); // "(2, 3)"
ちなみに入力用のシフト演算子(>>)を使えば 値 → 文字列 変換の from_str() のような関数も作れます。ただし、入力用の場合は変換できなかった場合の例外処理も必要になってきます。
実は Boost ではこの to_str()、 from_str() のような関数をもっと一般的にした lexical_castというのが用意されているので、 Boost 使えばすぐ使えるようになります。
Qt の場合だとこのようなテンプレートを使った変換は残念ながら用意されていないのですが、 Qt で用意されているクラスはほとんど QDebug というデバッグ用の出力先への演算子がオーバーロードされているので、何も定義しなくてもダンプだけならできます。
qDebug() << QPoint(2, 3); // "QPoint(2, 3)"
C++ のキャスト
C++ には 4 つのキャストがあります。
名称 | 説明 | 使用 |
---|---|---|
dynamic_cast | 基本クラスから派生クラスへのキャスト | 使用するべきではない |
const_cast | const を外すキャスト | 使用するべきではない |
static_cast | double から int など暗黙の変換のあるキャスト | 使用可 |
reinterpret_cast | double * から long long などの無理やりキャスト | なるべく使用しない |
個人的には、 C++ のキャストは書くのがめんどくさいし、 static_cast 以外はあまり使うべきではないのに static_cast は C のキャストだしってことで、 C 形式のキャストでいいんじゃねって思っています。
ただし、コーディング規約で決まっている場合などがあって使わないといけない場合とかもあると思います。
そこで、使い方を考えてみます。
書き方
C 形式のキャストの場合は対象に括弧を付ける必要はないのですが、 C++ 形式の場合は必ず付ける必要があります。ival = (int)dval; /* C */ ival = static_cast<int>(dval); // C++C++ のキャストは形式としては言語の機能というよりも templete 関数の一種のような見た目になってます。めんどくさいのですが、 Boost の lexical_cast のようにキャストっぽい関数をつくって形式を合わせることができるという利点もあります。
コードの見え方とコードの質
C に比べ、 C++ のキャストでは確かに書くのがめんどくさいなりましたが、あまりやるべきではないことはめんどくさくするのがいいという考え方もあります。例えば Ruby ではグローバル変数やクラス変数には必ず $, @@ を付ける必要があります。こういったものは沢山使っているとコードが汚く見えます。 グローバル変数などを大量に使うことはコードの質としてもダメです。
コードの質の悪いものは汚く見えるので、綺麗に見えるようにコードを書きます。 そうすれば、自動的にコードの質も上がってきます。
C++ でのキャストの使用
C++ のキャストも、 C++ の型安全性を無理やり壊すので、よくないものだと言われています。(『 Effective C++ 』)めんどくさいものは使いたがらなくなりますし、 C++ のキャストの汚さやめんどくささはいいことかも知れません。
もちろん、 めんどくさいから C 形式のキャストを使うということになるとだめなので、コーディング規約などで使用を強制しておく必要があります。
最初に言っていたことと違うことになってますが、一概にキャストはダメという訳ではないので、次回からこのキャストについて詳しく考えていきたいと思います。
![]() | Effective C++ 原著第 3 版 (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES) (2006/04/29) スコット・メイヤーズ 商品詳細を見る |
![]() | Boost C++ Libraries プログラミング (2007/07) 稲葉 一浩 商品詳細を見る |
![]() | オブジェクト指向スクリプト言語 Ruby (ASCII SOFTWARE SCIENCE Language) (1999/10) まつもと ゆきひろ、石塚 圭樹 他 商品詳細を見る |