> Dear C++ experts, I have few questions about cast operation.
Okay, a quick test on a compiler would have answered many of these
questions. However, let us press on, since we all know compilers are
never the answer, only the source of more questions.
> class A
> {
> private:
> Object* theGoal;
> public:
> Object* GetTheGoal() const { return theGoal; }
> ...
> };
Note that if you ever wish for there to be C::GetTheGoal() you should
declare this method virtual, otherwise it "hides" and you get different
behavior. And that's important.
> class B; // some other class
> class C: public A, public B // multiple inherited
> {
> ...
> };
> B* d = new C();
> Object* goal1 = ((A*)d)->GetTheGoal(); // cast B to A
> Object* goal2 = ((C*)d)->GetTheGoal(); // cast B to C
Okay, that's the source code. Let's assume that you do *not* declare a
method C::GetTheGoal. In that case, both operations will call
A::GetTheGoal (there's no other option). Both will compile fine.
BUT ...
To clearly understand what's going on, stop using C-style casts. Use C++
casts. You will find that you would be forced to use:
(reinterpret_cast<A*>(d))->GetTheGoal();
(static_cast<C*>(d))->GetTheGoal();
to compile. And you would clearly realize that you are doing a cast that
means more than just syntax to the compiler. And that you are simply
lucky because you do not have any virtual functions. A reintepreted cast
is a dangerous thing.
Let's throw virtuality into the mix.
Change A::GetTheGoal() to be virtual, and declare and define
C::GetTheGoal() to be different (so we can tell which is called).
Now, when the compiler tries to do the reinterpret_cast<A*>(d) (or for
that matter, the C-style cast), it seg faults because B and A are not
related. It can't do it the runtime reinterpretation. It's illegal.
Here's the very interesting example!
virtual A::GetTheGoal exists.
C::GetTheGoal also exists.
C *d = new C;
then:
d->GetTheGoal();
and
(static_cast<A*>(d))->GetTheGoal();
will *both* call C::GetTheGoal() !!!
To see a
But if you don't declare A::GetTheGoal as virtual, then:
d->GetTheGoal() --> C::GetTheGoal();
(cast to A*)(d)->GetTheGoal() --> A::GetTheGoal();
Different behavior.
Confused yet?
Let's sum up:
> 0. what cast from above is correct?
You should do neither. Casting B to A is illegal - they are not related.
Casting B to C is allowed, but should never be required (C inherits B
and thus can be used anywhere B is allowed) because not only is that the
point of inheritence, but can you guarantee that if someone passes you a
B* it's pointing to C? What if I declare D inheriting B and pass you a
D*?.
Casting C down to B is allowed, but depending on the data passing type,
you can "slice" off all the specific information to C and if you tried
to cast back from B to C would get garbage.
To quote Stroustrup:
"If you feel tempted to use an explicit type conversion, take the time
to consider if it is *really* necessary. In C++, explicit type
conversion is unnecessary in most cases when C needs it and also in many
cases in which earlier versions of C++ needed it."
Oh, and the difference of static_cast<>() and reinterpret_cast<>() is
the relation of types before and after the cast. A static cast would be
something like enum to int; a reinterpreted cast like integer to
pointer.
> 1. if there are rules to avoid segmentation violation errors?
Don't write illegal casts.
:-)
> 2. what is difference between declarations
> class C: public A, public B
> and
> class C: public B, public A
In QT or in C++ generally? In QT, it makes a difference to 'moc'. In
C++ it mandates the order in which base classes are constructed (unless
overridden by an initializer in a constructor). I think. Double-check. I
avoid multiple inheritance wherever possible.
> 3. if cast operation is platform/compiler dependent ?
The C++ casts are a part of the C++ specification. What is p/c dependent
is the way they are performed, especially when it comes to base and
derived classes and vtbl lookups.
-Michael
-- Michael J. Saletnik Software Engineer, AutEx, TFS Boston