473,503 Members | 1,656 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

virtual inheritance downcast

#include <iostream>
using namespace std;

class Base
{
public:
Base() {}
~Base() {}
};

class Derived : virtual public Base
{
public:
Derived() {}
~Derived() {}
};

int main()
{
Base *b = new Derived();
Derived *d = (Derived*)b; //line 22. The problem line!

return 0;
}

For the code above, I got the following error message:
downcast.cc: In function `int main()':
downcast.cc:22: error: cannot convert from base `Base' to derived type `
Derived' via virtual base `Base'

That means it is illegal to explicit convert a VIRTUAL base point to the
derived point. (non-virtual is ok) Can somebody explain it? ( The coding
style is bad, please just ignore it. ^_^)

Thanks in advance!
Apr 19 '06 #1
8 12630
fl****@gmail.com wrote:
#include <iostream>
using namespace std;

class Base
{
public:
Base() {}
~Base() {}
};

class Derived : virtual public Base
{
public:
Derived() {}
~Derived() {}
};

int main()
{
Base *b = new Derived();
Derived *d = (Derived*)b; //line 22. The problem line!

return 0;
}

For the code above, I got the following error message:
downcast.cc: In function `int main()':
downcast.cc:22: error: cannot convert from base `Base' to derived type `
Derived' via virtual base `Base'

That means it is illegal to explicit convert a VIRTUAL base point to the
derived point. (non-virtual is ok) Can somebody explain it? ( The coding
style is bad, please just ignore it. ^_^)


The compiler is correct - the conversion is illegal. Equivalently (and
more specifically), you cannot downcast a virtual base class pointer to
a derived class pointer using static_cast. This is because the case may
involve some pointer adjustment that depends on the dynamic type of the
object pointed to. e.g.

class Base
{
char i;
};

class Derived : virtual public Base
{
int j
};

class Derived2 : virtual public Base
{
int k;
};

class DiamondBottom: public Derived, public Derived2
{
int l;
};

int main()
{
Base *b = new DiamondBottom();
Derived *d = static_b; //line 22. The problem line!

return 0;
}

Now, in a DiamondBottom object, the Derived2 subobject is likely to be
placed after the Derived subobject, which means that the pointer
adjustment required for a conversion from a Base* to a Derived2* depends
on whether the Derived2 is part of a larger DiamondBottom object or not.

E.g. a Derived2 object looks like this (vtable pointers left out):
i
k

while a DiamondBotton object might look like this (vtable pointers left
out):
i
j
k
l

so that i and k are in different relative positions depending on the
dynamic type of the object.

The solution is to use dynamic_cast, which performs the correct
conversion by checking the real type of the object.

Tom
Apr 19 '06 #2
* fl****@gmail.com:
#include <iostream>
using namespace std;

class Base
{
public:
Base() {}
~Base() {}
};

class Derived : virtual public Base
{
public:
Derived() {}
~Derived() {}
};

int main()
{
Base *b = new Derived();
Derived *d = (Derived*)b; //line 22. The problem line!
Yes, don't use C-style casts. A C-style cast tells the compiler that
your Really Know What You're Doing. Which you absolutely don't, here.

return 0;
}

For the code above, I got the following error message:
downcast.cc: In function `int main()':
downcast.cc:22: error: cannot convert from base `Base' to derived type `
Derived' via virtual base `Base'

That means it is illegal to explicit convert a VIRTUAL base point to the
derived point. (non-virtual is ok) Can somebody explain it? ( The coding
style is bad, please just ignore it. ^_^)


Due to the virtual inheritance the Base sub-object can be a shared Base
sub-object for any number of Derived objects. So which one should the
cast produce a pointer to? There's no way to tell, strictly locally,
from the static type information, and for consistency the rules don't
distinguis situations like above where the compiler /could/ have figured
it out by looking at the rest of the program text.

So to do this you need access to run time type information, what the
object really is when the cast is attempted, and you need to allow for
failure.

And to do that, use a dynamic_cast (which requires at least one virtual
member function in Base, e.g. the destructor).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Apr 19 '06 #3

<fl****@gmail.com> wrote in message news:e2**********@news.cn99.com...
#include <iostream>
using namespace std;

class Base
{
public:
Base() {}
~Base() {} virtual ~Base() {} };

class Derived : virtual public Base
{
public:
Derived() {}
~Derived() {}
};

int main()
{
Base *b = new Derived();
Derived *d = (Derived*)b; //line 22. The problem line! Derived *d = dynamic_cast<Derived *>(b);

if you don't have virtual members in base class, then you can't use
dynamic_cast. In that case, reinterpret_cast is the only option but it will
cause undefined behavior on some platform...
return 0;
}

For the code above, I got the following error message:
downcast.cc: In function `int main()':
downcast.cc:22: error: cannot convert from base `Base' to derived type `
Derived' via virtual base `Base'

That means it is illegal to explicit convert a VIRTUAL base point to the
derived point. (non-virtual is ok) Can somebody explain it? ( The coding
style is bad, please just ignore it. ^_^)

Thanks in advance!

Apr 21 '06 #4
Fei Liu wrote:
dynamic_cast. In that case, reinterpret_cast is the only option but it will
cause undefined behavior on some platform...


The reinterpret_cast creates a value of a new type that has the SAME
BIT pattern as its argument so it will cause undefined behavior in ANY
platform, not some platforms from the base class to the derived class.

FYI, here is a test case:
======================
#include <iostream>
using namespace std;

class Base
{
public:
float base_v;
Base(): base_v(999) { }
~Base() {}

};

class Derived : virtual public Base
{
public:
int derived_v;
Derived(): derived_v(0) {}
~Derived() {}

};

int main()
{
Base *b = new Derived();
Derived *d = reinterpret_cast<Derived *>(b); //line 22. The
problem line!

cout << "b->base_v=" << b->base_v << endl;

//d->derived_v shows a weired result
cout << "d->derived_v=" << d->derived_v << endl;

// the following will throw segamentation fault!
cout << "d->base_v=" << d->base_v << endl;

return 0;
}
==============================

Apr 21 '06 #5
dan2online wrote:
dynamic_cast. In that case, reinterpret_cast is the only option but it
will
cause undefined behavior on some platform...
The reinterpret_cast creates a value of a new type that has the SAME
BIT pattern as its argument so it will cause undefined behavior in ANY
platform, not some platforms from the base class to the derived class.


....
class Derived : virtual public Base


Nice sample, but if you take the 'virtual' out, then on some platforms the
address of the Derived will be the same as the address of the Base within
it. You can assert for that.

In that situation, this rule takes effect: "reinterpret_cast works correctly
if it casts a pointer or reference to a type that an address truly
contains".

(Someone will doubtless look the correct verbiage up for me: My copy of the
old Standard is on my old hard drives.)

So in that narrow situation the behavior is defined.

--
Phlip
http://www.greencheese.org/ZeekLand <-- NOT a blog!!!
Apr 21 '06 #6

Phlip wrote:
dan2online wrote:

Nice sample, but if you take the 'virtual' out, then on some platforms the
address of the Derived will be the same as the address of the Base within
it. You can assert for that.


If the "virtual" disappears, the original example has no problem then.

Apr 21 '06 #7
Phlip wrote:
dan2online wrote:
dynamic_cast. In that case, reinterpret_cast is the only option but it
will
cause undefined behavior on some platform...


The reinterpret_cast creates a value of a new type that has the SAME
BIT pattern as its argument so it will cause undefined behavior in ANY
platform, not some platforms from the base class to the derived class.

class Derived : virtual public Base


Nice sample, but if you take the 'virtual' out, then on some platforms the
address of the Derived will be the same as the address of the Base within
it. You can assert for that.


If you leave the virtual in, it might still be the case. Of course, you
can't
compare a Derived* and a Base*; so for your assert you'd still need to
cast the other side of the comparison as well (or the first side back,
depending on how you write the assert). So the assert may cause
undefined behavior; it's a bit tricky to say without code.

Still, IIRC it's not the creation of the Derived* that will trip you,
but the actual
use as if it indeed points to a Derived*. You should be able to cast it
back to
the original Base*. Not very useful, I admit.

This doesn't matter a lot when it comes to Undefined Behavior and
platforms.
Undefined Behavior is what the ISO standard says about a piece of code.

If it's UB according to the standard, it's UB for all compilers, and if
not, for none.
(Disregarding trivial code like const int i = 4/sizeof(int)-4. A
division by zero is
still UB everywhere)

HTH,
Michiel Salters

Apr 21 '06 #8
Fei Liu wrote:

if you don't have virtual members in base class, then you can't use
dynamic_cast. In that case, reinterpret_cast is the only option but it will
cause undefined behavior on some platform...

Actually the C-style cast here will do a static_cast. This isn't
undefined as long as you know that the dynamic type really is
the type being cast to.
Apr 27 '06 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
6450
by: Stuart Golodetz | last post by:
Hi, I've got a minor casting issue which I need to check about (marked // <--). I was trying to do a static_cast on it (which didn't work, though I'm not sure why this should be the case?) I...
4
2881
by: JKop | last post by:
I'm starting to think that whenever you derive one class from another, that you should use virtual inheritance *all* the time, unless you have an explicit reason not to. I'm even thinking that...
14
1893
by: Bruno van Dooren | last post by:
Hi all, i am having a problems with inheritance. consider the following: class A { public: A(int i){;} };
9
1121
by: Joe | last post by:
Hello All: I work at an insurance company and we are changing the design of an ASP.NET application (for those have followed my postings, we're going to redesign some parts of the application -...
3
1697
by: Imre | last post by:
Hi! I've got some questions regarding heavy use of virtual inheritance. First, let's see a theoretical situation, where I might feel tempted to use a lot of virtual inheritance. Let's...
8
2166
by: Alex Vinokur | last post by:
Here is a code from http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.8 -------------------------------------- class Shape { public: virtual ~Shape() { } // A...
3
4532
by: kikazaru | last post by:
Is it possible to return covariant types for virtual methods inherited from a base class using virtual inheritance? I've constructed an example below, which has the following structure: Shape...
23
4577
by: Dave Rahardja | last post by:
Since C++ is missing the "interface" concept present in Java, I've been using the following pattern to simulate its behavior: class Interface0 { public: virtual void fn0() = 0; };
0
1293
by: =?Utf-8?B?Zmplcm9uaW1v?= | last post by:
Hi all, As I mentioned in a previous thread (see 'Dbghelp, symbols and templates' in microsoft.public.windbg), we created a powerful symbol engine using dbghelp to dump the contents of the stack...
0
7328
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
7458
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5578
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
5013
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
3167
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3154
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1512
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
736
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
380
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.