multiple inheritance wizardry

May 19, 2010 at 3:10pm
Hi

I'm a bit confused here :-|

The following code displays:
func_1
func_2


where I would expect it to display
func_2
func_2

Any explanation?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

class CA{
public:
	virtual void func_1() = 0;
};

class CB {
public:
	virtual void func_2() = 0;
};

class CC : public CA, public CB {
public:
	virtual void func_1() {
		std::cout << "func_1" << std::endl;
	}
	virtual void func_2() {
		std::cout << "func_2" << std::endl;
	}
};


int main (int argc, const char* argv[])
{
	CA* a = (CA*) new CC();
	CB* b = (CB*) a;
	b->func_2();

	CB* b2 = (CB*) new CC();
	b2->func_2();

	return 0;
}
May 19, 2010 at 3:16pm
Hi scapal,

The reason is that there is no runtime type check to determine how to cast a CB* to a CA* with a c-style cast, so your 'b' above is actually pointing to the CA portion of the CC object, rather than the CB portion. I am pretty sure the above will work if you do either:

CB * b = dynamic_cast<CB*>(a);

or

CB * b = (CB*)((CC*)a);

-Rollie
May 19, 2010 at 3:29pm
Thanks Rollie :-)
May 19, 2010 at 6:05pm
the proper C++ way of doing that cast
 
CB * b = (CB*)((CC*)a);

(without runtime penalties) is
 
CB* b = static_cast<CB*>(static_cast<CC*>(a));


I think since this is c++ we should try to stick to it ;-)

Plus the C++ casts are better to see and find in code. And they are less "evil".
May 19, 2010 at 6:15pm
If we're sticking to C++, stick to dynamic_casts, too...safety first.
May 19, 2010 at 8:20pm
dynamic_casts have an run-time overhead not needed in this situation since the inheritance is clear at run-time.
May 19, 2010 at 8:26pm
From the first message, in the real situation, a concrete class CC is created from a factory and the result is given as an abstract class pointer CA*.
Then to get a CB* pointer from that, without knowing what is the concrete class (here CC), you need a dynamic_cast.

May 19, 2010 at 8:40pm
dynamic_casts have an run-time overhead not needed in this situation since the inheritance is clear at run-time.

That's a poor excuse. You should not take it upon yourself to circumvent the run-time checks unless there is clear hard data that you have to--and even then, I would think long and hard about it and comment the entire reasoning.

The static_casts above (if they even work) are more verbose, their intent is less clear, and they are the beginning of a future gotcha.
Last edited on May 19, 2010 at 8:41pm
May 19, 2010 at 8:42pm
Explicit type casting is an "evil" feature. Treat it well, and it will grant you many a ways to shorten your code and do more with it. Treat it poorly, like you did, and it will send its digital foot straight up your I/O ports.

dynamic_cast<>() is the way to go. static_cast<>() also works, but it's a bit less safe, even if it's faster.
http://cplusplus.com/doc/tutorial/typecasting/

-Albatross
Last edited on May 19, 2010 at 8:45pm
May 19, 2010 at 8:55pm
Static casts may be faster (~30x faster), but unless you are performing the cast thousands of times per second, IMO better to go with the safer dynamic_cast. In a quick test, I was able to perform 10,000,000 dynamic casts in under 1 second. Calling the entirely wrong method on an object, however, could be catastrophic from a business perspective (for example, if you call 'base1::get_yesterdays_price()' instead of 'base2::get_todays_price()'.)

-Rollie
May 20, 2010 at 10:46am
dynamic_casts and static_casts are, i know people will complain about this, the same.
They differ only in where they solve the inheritance graph.

dynamic_casts do it at run-time whereas static_cast will resolve them at compile-time.

If you can "see" the inheritance at compile time use static_cast! It will NOT let you compile your code unless the classes are inherited.

If you are implementing code, i.e. for a library, and you are not sure whether the object you will be getting is derived from a certain class, that's the time to use dynamic_cast (don't forget to check for return NULL). And 30x slower is 30x slower. Why should you pay for this overhead if it is not needed?

static_cast<>() also works, but it's a bit less safe


Less safe then what? C-style casts? Yes. Static_cast? No.
Topic archived. No new replies allowed.