キャストとコンストラクタの違い?

[戻る]
bun 2009/10/23(金) 09:45:28
今さらのようにふと疑問に思ったのですが、キャストとコンストラクタによる
初期化って違いはあるんでしょうか?

(例)
以下のようなenumがあるとき、
  enum EColor
  {
    Red    = 1,
    Blue   = 2,
    Yellow = 3,
  };

  EColor eClr = (EColor)2;
  で初期化することと
  EColor eClr = EColor(2);
  で初期化することの違いです。

クラスのときは、コンストラクタかコピーコンストラクタの違い?
だとして、どっちを選んでも差はない?

まぁ、「どっちでもいいやろ」と言われてしまえば、それまでの話なのですが
蛇足ですいません(;^_^A;

仲澤@失業者 2009/10/23(金) 11:06:49
回答ではありません。あしからず(^^;)。

質問の内容においては、enumは適当な例とはいえません。
なぜなら、enumやunionを継承したクラスは作れないので、
比較が容易にできませんよねぇ。
実際に疑問に思ったときのコードを上げてみてはどうでしょう。

bun 2009/10/23(金) 14:25:58
実際に疑問に思ったのは、上記のenumの例になります。
クラスの話は疑問を抱いてから、自分で考えを広めたものです。

また、そもそも、この話の前提として、
組込型(int, enum, float, ...)とクラス型(class, struct, ...)を分けるべき
かどうかというところも疑問のうちではあります。

私としては組込型とクラス型を分けて考える必要はないのかな?
と思って、上記の質問となります。

maru 2009/10/23(金) 16:34:37
キャストは明示的変換演算子なので
class_A a;
class_B b = (class_B)a;
の時、class_Aにclass_Bへの明示的変換:
  class_A::operator class_B() const;
が必要ですよね。この関数の内部でclass_Bのコンストラクタが使用されるでしょうね。
で、この変換関数が存在しなけば、コンパイルエラーになる。
ただし、class_Bにclass_Aを受け入れるコンストラクタ:
  class_B(const class_A& a);
が有れば、そちらが使用される。

ということではないですか?

bun 2009/10/23(金) 17:47:44
[[解決]]
ちょっと、質問内容が漠然としすぎていた気がします。
失礼しました。

要は、
  1) EColor eClr = (EColor)2;
  2) EColor eClr = EColor(2);
どっちの書き方が、より好ましいか?
を迷ったということです。

どっちでもいいような気がするけど、
もしかしたら新発見があるかもと思って質問させていただきました。

「どっちでもいいやろ」
が結論であればクローズとしたいと思いますm(__)m

subaru 2009/10/23(金) 17:54:57
>要は、
>  1) EColor eClr = (EColor)2;
>  2) EColor eClr = EColor(2);
>どっちの書き方が、より好ましいか?
>を迷ったということです。

言語仕様とかは自信が無いですが、
http://msdn.microsoft.com/ja-jp/library/cc440191(VS.71).aspx
の「暗黙のキャスト」の部分を読むとやはり結果的には全く同じようです。
ここの説明では、static_cast の方が危険な操作をしている部分を
後から識別しやすいですよという意味・・・なのかなあ(?)

仲澤@失業者 2009/10/23(金) 19:28:35
(あ) EColor eClr = (EColor)2;
(い) EColor eClr = EColor(2);

EColorがenumなので、上記はどちらも「キャスト」です。
下は最近可能になった書き方ですね。
いつから可能になったのかは忘れちゃいました( =>>誰か)。

さて、やってみればすぐわかりますが、EColorがクラスの場合。(あ)も(い)も

 「コンストラクタ EColor( int)「等」があればそれが実行されるが、
   なければコンパイルエラーになる」

だけです。こちらは両方ともコンストラクタ EColor( int)「等」と
解釈されました(VS2008)。

自分としては、クラスの場合は(あ)も(い)もわかりづらいので使いません。

  EColor eClr(2); // クラスの場合

と書きますね。これならEColorがenumの場合、コンストラクタがないので、
コンパイルエラーになってくれます。当該のコンストラクタがない場合の
クラスも同様です。逆にenumの場合には、極力キャストしないようにしてます。
せっかく書いた定義なので(vv;)。
で、あえて使うとしたら(あ)ですかねぇ。

蛇足ですが、
classに対してのキャストは、現在では
 (1)型B  b = static_cast<  型B>( 型Aのインスタンス);    // 従来のcast
 (2)型B  b = dynamic_cast< 型B>( 型Aのインスタンス);  // 主にDown Cast用
 (3)型A a = const_cast<   型A>( constな型Aのインスタンス); // const外し用
 (4)型B* b = reinterpret_cast< 型B*>( 型Aのインスタンス); // 使うな(らしい)
の4つを使うように推奨されてるそうですが、VCの場合RTTIをOnにしないと
使えなかったりするので、あまり使ってませんね(vv;)。

bun 2009/10/23(金) 21:51:33
>の「暗黙のキャスト」の部分を読むとやはり結果的には全く同じようです。
全く同じですか。
であれば、私はずっと上を使ってきたので、今後もそちらで行こうと思います。

> 下は最近可能になった書き方ですね。
そうなんですね。

>クラスも同様です。逆にenumの場合には、極力キャストしないようにしてます。
>せっかく書いた定義なので(vv;)。
まったく、仲澤@失業者さんのおっしゃるとおりだと思います。
下手にINTとかにキャストするとデバッガで[Red]とか表示されなくなって分かり
づらいことこの上ない。

実際のソースコード上でも、バイナリデータとして保存/読み出しの前後だけ、
固定長のDWORD型にキャストしており、その前後のキャストの話になります。

ありがとうございました。

Ban 2009/10/25(日) 06:37:41
# 重箱の隅的な話です。

> EColorがenumなので、上記はどちらも「キャスト」です。

言語仕様(ISO/IEC14882:2003)上の定義で言えば、
「明示的型変換(explicit type conversion)」に以下の3種類があるので、
・関数形式(functional notation)
・キャスト形式(cast notation)
・型変換演算子(type conversion operator)
単にキャストといえば、cast notationの1)だけを指すと解釈するべきかなと思います。

 1) (EColor)2; // $5.4 Explicit type conversion (cast notation)
 2) EColor(2); // $5.2.3 Explicit type conversion (functional notation)

効果的には5.2.3は5.4の対応するキャストと等価だと規定されていますし、
現実的には全部ひっくるめてキャストと呼ばれることも多いと思いますけれど。

ちなみに、explict type conversionはenumでもclassでも特に区別はなさ気。


> の4つを使うように推奨されてるそうですが、VCの場合RTTIをOnにしないと
動作上RTTIが必要なのはdynamic_castだけですね。
# 私の場合は言語の機能をOFFにするのが気持ち悪くてOffにはしてません>RTTI

で、「classに対して」に限らず、言語設計者は全般的に1でも2でもなく、
演算子(…_cast類)の使用を薦めてますよね。
# 例えば"_cast"で検索できたり、典型的な誤変換がエラーになったりするので、
# 「何でもできてしまう」上に「識別しにくい」castは好ましくないという発想。

関数形式はtemplateだかで型を画一的に取り扱うために導入されたような…(うろ覚え

Ban 2009/10/25(日) 06:51:26
> 2) EColor(2); // $5.2.3 Explicit type conversion (functional notation)

ちなみに、これでもし引数が複数あれば、初期化とみなされます。
Foo foo =Foo(2,2); はFoo foo(2,2);と等価。

ロマ 2009/10/25(日) 12:58:40
関数形式は、初版からあります

仲澤@失業者 2009/10/26(月) 10:25:27
Banさん詳しい説明ありがとうございます。
># 私の場合は言語の機能をOFFにするのが気持ち悪くてOffにはしてません>RTTI

確かに、VCも2005あたりからデフォルトでONになってますしね(vv;)。

ロマさん
>関数形式は、初版からあります

ですか、どのコンパイラでしょう。
バージョンは忘れましたが、自分が最初に使ったコンパイラ「Lattice C」は
int( a); はおろか return 0;も使えませんでした(笑)。
それを下敷きにしたと思われるMS-Cのv2.xもだめでした。
少し下ってTurbo C v1.5(サザン版・・・だったかな)も
だめだったような気のせいがします。

bun 2009/10/26(月) 11:34:44
>関数形式は、初版からあります

>バージョンは忘れましたが、自分が最初に使ったコンパイラ「Lattice C」は
int( a); はおろか return 0;も使えませんでした(笑)。

何となくですが、ロマさんは C++ の初版と言っていて、
仲澤@失業者さんは C言語の話をしているのかな?

ロマ 2009/10/26(月) 13:55:55
規格制定より前の、
「プログラミング言語C++」(トッパン1988)(原著は1986?)の仕様です
第1版とか1095年版と書いたほうがよいのかな、良くわかりません

ロマ 2009/10/26(月) 13:57:02
> 1095年版
1985年版でした

仲澤@失業者 2009/10/26(月) 17:38:02
bunさん
>何となくですが、ロマさんは C++ の初版と言っていて、
>仲澤@失業者さんは C言語の話をしているのかな?

おっと(^^;)。C++から可能になったんですね。
恥ずかしながらすっかり忘れてました。ありがとうございます。

ロマさん
>1985年版でした

この頃はC++コンパイラではなく、C++からC言語への
コンバータぐらいしか触ってないので、気がつきません
でした。のVC++1.0からですかね。自分は。

古いスレッドには追加発言できません。