Meir
Meir

Reputation: 12755

casting producing const objects in c++

Would it be correct to say that whenever casting is used, the resulting object is a const object?

...And therefore can only be used as an argument to a function if that function accepts it as a const object?

e.g.

class C1 {
    public: C1(int i=7, double d = 2.5){};
};

void f(C1& c) {};

int main(){
    f(8);
    return 1;
}
//won't compile

(Of course if f(....) receives the argument by value then it gets a non-const version which it can work with)

Upvotes: 1

Views: 717

Answers (3)

Faisal Vali
Faisal Vali

Reputation: 33673

Usually when an object of a certain type is converted to an object of another type (a non-reference type), a temporary object is created (not a const object). A temporary object (invisible, nameless, rvalue) can only bind (in C++98/03) to references that are const (except for the temporary known as the 'exception object'). Therefore, the result of a conversion that creates a temporary can only be used as an argument to a function that either accepts it as a const reference, or as a type that it can be copied/converted into.

So for e.g.

void f(double);  // 1
void f(const int&); // 2
void f(int&); // 3

struct B {  B(int) { } };
struct C { C(int)  { } };
void f(B b);  // 4
void f(B& b); // 5
void f(const C& c); //6
void f(C& c); // 7

// D inherits from B
struct D : B { D(int) : B(0) { } };
void f(D& d); // 8

int main()
{
   f( (int) 3.0 ); // calls 2, NOT 3
   f( (float) 3 ); // calls 1 - const reference requires the same type
   f( 1 );  // calls 2, NOT 3

   f( (B) 1 ); // calls 4, not 5 - can accept it by non-const value
   f( (C) 1 ); // calls 6, not 7 - can accept it by const-reference

   f( (D) 1 ); // calls 4, not 8 - since a 'D' temporary object can be converted to a 'B' object - but will not bind to a non-const reference
}

Hope that helps.

Upvotes: 12

Ethan
Ethan

Reputation: 546

It's a little off to call this 'casting'. You are doing 'implicit construction'. Implicit construction always creates a temporary object, which in turn is always const.

Note you can mark the constructor 'explicit' and this would block the implicit construction call you're seeing here. But that only means you would need f(C(8)) instead of f(8); the C instance would still be const because it is temporary, however note no cast is being done.

See also const_cast for dirty workarounds if you really, really need to. The other workaround would be to do a two liner: C c(8); f(c);

Upvotes: 3

ChrisW
ChrisW

Reputation: 56113

You can rewrite that as:

class C1
{
    public: C1(int i=7, double d = 2.5){};

};

void f(C1& c){};

int main()
{
    C1 c(8); //named
    f(c);
    //... can access the modified C1 instance here ...
    return 1;
}

The thing that the compiler doesn't like about your version is that your C1 instance is an un-named temporary: which f will modify, but (because it's an un-named temporary) the compiler knows that the caller (main) has no way to receive/preserve/notice those modifications.

Upvotes: 0

Related Questions