2009-09-05 23 views
28

C++の変換演算子がどのくらい正確に機能するか理解してください。 私は理解しようとしているここでは単純な例がありますが、実際にどのように変換がコンパイラによって行われるかははっきりしていません。C++の変換演算子

class Example{ 
public: 
    Example(); 
    Example(int val); 
    operator unsigned int(); 
    ~Example(){} 
private: 
    int itsVal; 
}; 

Example::Example():itsVal(0){} 

Example::Example(int val):itsVal(val){} 

Example::operator unsigned int(){ 
    return (itsVal); 
} 

int main(){ 
    int theInt = 5; 
    Example exObject = theInt; // here 
    Example ctr(5); 
    int theInt1 = ctr; // here 
    return 0; 
} 
+16

と同等です:私はあなたが 'std名前空間を使用している気づく;'ファイルの先頭近く。私は、あなたの講師や教材にこれが好きだと推測しています。この例では必要ではありませんが、使用する場所には注意してください。 **ヘッダーファイルでこれを使用することは決してありません - あなたは 'std'名前空間にある名前を自分自身で使いたいなら、悲しみを抱かせることがあります。あなたは私のような場合は、モジュール(.cppファイル)とすべての#includeの後で、関数とメソッドの定義の前に使用したいと思うかもしれません。 – quamrana

+0

あなたの質問は何ですか? –

答えて

4
Example exObject = theInt; // implicitly created copy constructor takes place 
// object implicitly created from int and then copied 
// it is like 
Example exObject = Example(theInt); 
// so it uses sequence 
// Example(int) -> Example(const Example&) 
int theInt1 = ctr; // operator int() 

あなたは支持体には、コンストラクタの最適化および戻り値の最適化をコピーするコンパイラの場合は、

Example(const Example&) 

実行を気付くことはありませんが、あなたは私が話しているかを理解するために、民間するコピーコンストラクタを宣言することができます約。

+2

例(int)はコピーコンストラクタではありません。 –

+0

例(int)はありませんが、例の例は= intです。暗黙的に作成されたコピーコンストラクタを使用します。 –

+3

コピーctorは[const]例&を第1引数としてとります。この場合、コンパイラは暗黙的に引数を持つ通常のctorであるExample(int)を暗黙に呼び出します。 –

9

デバッガでそのコードを歩く(および/または各コンストラクタと演算子にブレークポイントを設定する)ことで、コンストラクタと演算子のどちらがどの行から呼び出されているかを確認できます。

明示的に定義していないため、コンパイラは隠された/既定のコピーコンストラクタとクラスの代入演算子も作成しました。デバッガを使用してどこで呼び出されているかを確認する場合は、これらを明示的に定義できます(次のように)。

Example::Example(const Example& rhs) 
: itsVal(rhs.itsVal) 
{} 

Example& operator=(const Example& rhs) 
{ 
    if (this != &rhs) 
    { 
     this->itsVal = rhs.itsVal; 
    } 
    return *this; 
} 
+0

RVOをオフにする方法は知っていますか? –

+0

次の2行が私を殺しています。 例exObject = theInt; int theInt1 = ctr; このプログラムではコピーコンストラクタが呼び出されていますが、代入演算子はどのようになっていますか?彼らのどれも呼ばれるようではありません。 – Zuzu

2
Example exObject = theInt; // here 

これは、INTを受け入れ、非明示的なコンストラクタによって行わ例にint型の暗黙的な変換を使用します。

この例では、コンパイラーがインスタンスのコピーを省略できる場合でも、例のコピーコンストラクターが使用可能である必要があります。

int theInt1 = ctr; // here 

これは、キャスト演算子によって提供されるExampleからunsigned intへの暗黙的な変換を使用します。

通常、キャスト演算子は混乱しやすいコードになりがちで、単一引数のコンストラクタを明示的にマークしてクラスの型への暗黙的な変換を無効にすることができるため、回避されます。 C++ 0xは、変換演算子を明示的にマークする可能性も追加する必要があります(私のコンパイラはそれらをサポートしていませんし、すべてのWebリソースは明示的なブール変換に集中しているようです)。

5
int main() { 
    int theInt = 5; 

    /** 
    * Constructor "Example(int val)" in effect at the statement below. 
    * Same as "Example exObject(theInt);" or "Example exObject = Example(theInt);" 
    */ 
    Example exObject = theInt; // 1 

    Example ctr(5); 

    /** 
    * "operator unsigned int()" in effect at the statement below. 
    * What gets assigned is the value returned by "operator unsigned int()". 
    */ 
    int theInt1 = ctr; // 2 

    return 0; 
} 

コンストラクタExample(int val)が呼び出されます。 explicit Example(int val)と宣言すると、コンパイル時エラーが発生します。つまり、暗黙の変換はこのコンストラクタでは許可されません。

割り当てられた値がそれぞれの引数型の場合、すべての単一引数のコンストラクタが暗黙的に呼び出されます。単一の引数コンストラクタの前にexplicitキーワードを使用すると、暗黙のコンストラクタ呼び出しが無効になり、暗黙の変換が無効になります。

コンストラクタが明示的に宣言された場合、つまりexplicit Example(int val)の場合、各文に対して次のようになります。

Example exObject(theInt); // Compile time error. 
Example exObject = theInt; // Compile time error. 
Example exObject(Example(theInt)); // Okay! 
Example exObject = Example(theInt); // Okay! 

また、暗黙のコンストラクタコールの場合、暗黙の変換の場合、割り当てられた値はrvalueです。非指定されたオブジェクトは、暗黙のうちにドン」(C++ 11に)暗黙の型変換の場合には、コンパイラがそう

Example exObject = Example(theInt); 

Example exObject = theInt; 

を変換していることを教えてくれる左辺値(theInt)を使用して作成しましたlvalueコンストラクタが呼び出されることを期待しています。左辺値、つまり割り当てのために名前付き値theIntを使用しています。割り当てられた値は実際には左辺値を使用して作成された名前のないオブジェクトなので、右辺のコンストラクタが呼び出されます。ただし、lvalueとrvalueの両方のコンストラクタがある場合は、これが適用されます。

at文2 operator unsigned int()が呼び出されます。奇妙な名前を持つ通常の関数呼び出しと、暗黙的な変換が発生したときに自動的に呼び出されるという事実を考えてください。その関数が返す値は、式に代入された値です。そしてあなたの実装では返される値は正しくint theInt1に割り当てられるintです。

正確にはoperator unsigned int()は、キャスト演算子である()演算子をオーバーロードします。あなたのケースでは、intのためにオーバーロードされます。したがって、Exampleクラスのオブジェクトがintに割り当てられると、Exampleからintへの暗黙の型キャストが発生し、したがってoperator unsigned int()が呼び出されます。したがって、

int theInt1 = ctr; 

は@Zuzu

int theInt1 = (int)ctr; 
+1

例exObject(theInt);たとえコンストラクタが明示的であっても、私はコンパイル時エラーではないと思います。直接初期化は許可されています。 – bornfree

+0

これは奇妙です: '例exObject(例(theInt));'。それが正しいと思いますか? 'Example exObject((Example)theInt);を書くことを意図していたかもしれません。 – mathiasfk