29

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;
}
4

4 に答える 4

9

デバッガーを使用してそのコードをウォークスルーし (および/または各コンストラクターと演算子にブレークポイントを配置)、どのコンストラクターと演算子がどの行で呼び出されているかを確認できます。

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

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

Example& operator=(const Example& rhs)
{
    if (this != &rhs)
    {
        this->itsVal = rhs.itsVal;
    }
    return *this;
}
于 2009-09-05T15:58:57.447 に答える
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;
}

ステートメント 1 で、コンストラクター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!

また、暗黙的なコンストラクター呼び出し、つまり暗黙的な変換の場合、割り当てられた値は右辺値、つまり左辺値 (theInt) を使用して暗黙的に作成された名前のないオブジェクトであることに注意してください。これは、暗黙的な変換の場合、コンパイラーが変換することを示しています。

Example exObject = theInt;

Example exObject = Example(theInt);

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

at ステートメント 2operator unsigned int()が呼び出されます。奇妙な名前の通常の関数呼び出しと、暗黙的な変換が発生したときに自動的に呼び出される可能性があるという事実と単純に考えてください。その関数によって返される値は、式で割り当てられた値です。また、実装では返される値は int であるため、正しく割り当てられint theInt1ます。

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

int theInt1 = ctr;

と同等です

int theInt1 = (int)ctr;
于 2013-03-03T17:20:58.483 に答える
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&)

ただし、私が話していることを理解するために、コピー コンストラクターをプライベートに宣言することができます。

于 2009-09-05T15:39:26.957 に答える
2
Example exObject = theInt; // here

これは、int を受け入れる非明示的なコンストラクターによって影響を受ける、int から Example への暗黙的な変換を使用します。

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

int theInt1 = ctr; // here

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

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

于 2009-09-05T17:21:05.577 に答える