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.