stella
stella

Reputation: 2596

Understanding casting in C++

I came from Java, so when need to call a function like this:

struct A {
    int a;
    A(int a) : a(a){ }
};

A foo(A a){
    return A(a);
}

I tend to write something like

A a = foo(A(10));

and it works perfectly fine. But I learnt that it can also be done in this way::

A a = foo(static_cast<A>(10));

I.e. it enforces the implicit conversion. So, as a rule of thumb should we alsways use static_cast-style when we need to exploit implicit conversion? Or there are some cases where function/C-style casts may be necessary?

Upvotes: 1

Views: 120

Answers (3)

ABu
ABu

Reputation: 12249

When you want to do a conversion from type A to B, you have two syntaxes to define the conversion:

class B
{
public:
    B(A); # Conversion constructor.
};

or

class A
{
public:
    operator B(); # Conversion operator.
};

For a case like:

void f(B b);

int main()
{
   A a;
   f(a);
}

If the first version exists, it creates a temporary object of class B, using a as parameter. If the second version exists (and you implement it, of course), it calls the operator B() of class A to create an object of type B from a. If both exists, the compiler throws you a message of ambiguity error.

About down/up-casting, implicit conversions allow upcasting (if source and target types are references/pointers), even if the target base is an innacesible (private) base class of the source. Implicit conversions also allow conversion from a non-const source type to a const target type, or also conversion from rvalue to lvalue and so on.

These are, in short, the rules of implicit conversions. A more complete guide (considering built-in versus user-defined types and built-in conversions) is here.

If you use the C++-casting:

f(static_cast<B>(a));

its nearly the same but with some differences: if B is an innaccesible (private) base of a, the cast isn't allowed. The other difference is that downcasting is allowed without runtime check (if B is a derived class of A it allows the casting, even if a isn't actually an object of type B). That is allowed because runtime check is slow, so, if you KNOW a is actually of type B, you can safely apply the casting without runtime check.

Other castings are:

const_cast<B>(a)

Only to change from const to non-const and viceversa.

reinterpret_cast<B>(a);

Cast everything. Nearly no rules involved. If a conversion from a to B doesn't exists, it just takes the memory region of a and returns it as an object of type B. Its the fastest cast alive.

dynamic_cast<B>(a);

Downcasting with runtime check (both types must be references or pointers). If the real type of a isn't B (not even a base class of the real type of a), an exception or null pointer is thrown/returned (according to if a or B are references or pointers).

Lastly, the C-casting:

f((B)a);

What the C-casting does is to try different castings (except dynamic_cast, and also allowing casting to innacesible base classes) and use the first which works. I would say the C-casting is as powerful as the implicit cast.

The explicit casting with syntax of funcion call:

f(B(a));

is equivalent to the C-casting in behaviour.

Upvotes: 2

Tony Delroy
Tony Delroy

Reputation: 106068

There are two separate aspects worth (re)consideration here: should A::A(int) be left implicit, and how best to construct an A to pass to foo.

For the former, there's no way of deciding without knowing the usage A should support, but it's generally recommended to err on the side of having explicit constructors if unsure.

For construction, use A(10) (with C++11, A{10} works too), or just 10 to rely on the implicit conversion. Note that A(10) is a constructor call not a cast: there's no need to consider static_cast<>() as a preferred casting notation. The old C-style cast notation is actually (T) cast-expression, per 5.4 [expr.cast] in the C++ Standard.

Upvotes: 2

John Zwinck
John Zwinck

Reputation: 249113

You never need C-style casts in C++. As for your examples, the most common way to write it would be this one:

A a = foo(A(10));

Upvotes: 3

Related Questions