简体   繁体   中英

Why does C++ choose to cast my return value to int?

For various boring reasons, I need a boxed int class that mostly acts as an int, but is a class that inherits from a base so it can work with other parts of a object hierarchy. I included a constructor that takes an int, as well as an int cast so I can easily intermix my boxed int with regular ints in code. However, I'm seeing a very odd behavior that I can't figure out: When I return my boxed int from a function, I'd like it to use my copy constructor that takes a reference to another BoxedInt. However, instead it casts my boxed int to and int, and then uses my int constructor. This causes problems because in my actual codebase, there are other baseclass properties I want to copy in this case, and they are lost by taking this cast/constructor path. Here is the code in question:

class BoxedInt
{
private:
    int m_int;
public:
    BoxedInt():m_int(0)
    {
        trace(L"Constructed with nothing");
    }

    BoxedInt(int val):m_int(val)
    {
        trace(L"Constructed with int");
    }

    BoxedInt(BoxedInt& val)
    {
        trace(L"Constructed with reference");
        m_int = val.m_int;
    }

    operator int()
    {
        trace(L"Cast to int");
        return m_int;
    }
};

BoxedInt funky()
{
    BoxedInt TempInt = 1;
    return TempInt;
}

int main(int argc, char* argv[])
{
    trace(L"Start");
    BoxedInt test1 = 1;
    trace(L"Copying");
    BoxedInt test2 = test1;
    trace(L"Assigning from return value");
    BoxedInt test3 = funky();
    trace(L"Done");
    return 0;
}

When this is run, here's the output:

Start
Constructed with int
Copying
Constructed with reference
Assigning from return value
Constructed with int
Constructed with reference
Cast to int
Constructed with int
Done

So when I assign one value to another, the reference based constructor is used, as I'd expect. However, when I assign the return value of my function to a BoxedInt, for some reason the compiler decides to cast to int, then use the int constructor. My C++ is rusty and I'm having trouble getting to the bottom of this odd compiler decision that I can't seem to counteract. Any ideas?

Your copy constructor takes a reference to a non-const, so it cannot be called with a temporary. The return value of funky() is a temporary, so the copy constructor cannot be used to construct test3 .

Make the copy constructor take a const reference, and it should be OK.

Your copy-constructor takes a non-const reference, which means you can't bind a temporary to the parameter, which is exactly what your desired method of returning would do. Therefore, the compiler chooses the other route.

Change your copy-constructor:

BoxedInt(const BoxedInt &val) {

In fact, Clang 3.4 gives an error because of the BoxedInt test1 = 1; .

I believe the issue (or one of them) is the copy constructor signature:

BoxedInt(BoxedInt& val)

It should be

BoxedInt(const BoxedInt& val)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM