473,401 Members | 2,125 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,401 software developers and data experts.

downcast?

Why doesn't the following throw an exception. It seems like you
should not be able to downcast from A to B since A is not a B.

#include <iostream>

using namespace std;

class A {
public:
virtual void first();
};

class B: public A {
public:
void first();
void second();
};

void A::first() {
cout << "A::first()" << endl;
}

void B::first() {
cout << "B::first()" << endl;
}

void B::second() {
cout << "B::second()" << endl;
}

int main() {
A* a = new A;
B* b = (B*)a;
b->second();
return 0;
}
Jul 29 '08 #1
9 2288
On Jul 29, 12:26*pm, cron...@gmail.com wrote:
Why doesn't the following throw an exception. *It seems like you
should not be able to downcast from A to B since A is not a B.

#include <iostream>

using namespace std;

class A {
public:
* *virtual void first();

};

class B: public A {
public:
* *void first();
* *void second();

};

void A::first() {
* *cout << "A::first()" << endl;

}

void B::first() {
* *cout << "B::first()" << endl;

}

void B::second() {
* *cout << "B::second()" << endl;

}

int main() {
* *A* a = new A;
* *B* b = (B*)a;
* *b->second();
* *return 0;

}

First, from base to derived (A to B) is called an "upcast", not a
"downcast".
Second, you should not do
B* b = (B*)a;
but instead use one of those fancy C++ casters, dynamic_cast I think,
but I never use them because I understand C :)
Probably something like: B* b = dynamic_cast<B*>(a);
And third, it doesn't crash, and actually works perfectly fine,
because the second() method does not use any instance data of a/b.
The "this" 'keyword' is just pushed on the stack as a hidden argument,
but since second() does not access 'this', it acts like a static
method.

If you would have done this:
class B: public A {
public:
void first();
void second();

int mInstanceData;
};

void B::second() {
cout << "B::second()" << mInstanceData << endl;
}

then the following should crash, yes:

int main() {
A* a = new A;
B* b = (B*)a;
b->second();
return 0;
}
Cheers!
-- raicuandi
Jul 29 '08 #2
On Jul 29, 12:26*pm, cron...@gmail.com wrote:
Why doesn't the following throw an exception. *It seems like you
should not be able to downcast from A to B since A is not a B.

#include <iostream>

using namespace std;

class A {
public:
* *virtual void first();

};

class B: public A {
public:
* *void first();
* *void second();

};

void A::first() {
* *cout << "A::first()" << endl;

}

void B::first() {
* *cout << "B::first()" << endl;

}

void B::second() {
* *cout << "B::second()" << endl;

}

int main() {
* *A* a = new A;
* *B* b = (B*)a;
* *b->second();
* *return 0;

}

Btw, to continue, this means that nomather what value you have in the
pointer 'b', it would still work. Including NULL.

B* b = (B*)NULL;
b->second(); // works, because B::second does not access any instance
data
Jul 29 '08 #3
cr*****@gmail.com wrote:
Why doesn't the following throw an exception. It seems like you
should not be able to downcast from A to B since A is not a B.

#include <iostream>

using namespace std;

class A {
public:
virtual void first();
};

class B: public A {
public:
void first();
void second();
};

void A::first() {
cout << "A::first()" << endl;
}

void B::first() {
cout << "B::first()" << endl;
}

void B::second() {
cout << "B::second()" << endl;
}

int main() {
A* a = new A;
B* b = (B*)a;
b->second();
return 0;
}
You have undefined behaviour. a is not a B, so calling b->second() is
undefined.

You should use dynamic_cast to cast form an A* to a B*. In your example
above, dynamic_cast would fail and b would be NULL. If you were to try
and dynamic_cast to a reference, you would get a bad_cast exception:

B& b = dynamic_cast<B&>(*a);

--
Ian Collins.
Jul 29 '08 #4
On Jul 29, 6:36 am, raicuandi <raicua...@gmail.comwrote:
On Jul 29, 12:26 pm, cron...@gmail.com wrote:
Why doesn't the following throw an exception. It seems like
you should not be able to downcast from A to B since A is
not a B.
#include <iostream>
using namespace std;
class A {
public:
virtual void first();
};
class B: public A {
public:
void first();
void second();
};
void A::first() {
cout << "A::first()" << endl;
}
void B::first() {
cout << "B::first()" << endl;
}
void B::second() {
cout << "B::second()" << endl;
}
int main() {
A* a = new A;
B* b = (B*)a;
b->second();
return 0;
}
First, from base to derived (A to B) is called an "upcast", not a
"downcast".
I've always heard it called a downcast. Maybe because in class
diagrams on paper, the base classes are usually at the top of
the page; I don't know. But I find it confusing as well.
Second, you should not do
B* b = (B*)a;
but instead use one of those fancy C++ casters, dynamic_cast I
think, but I never use them because I understand C :)
Definitely. What he's written here is a static_cast. Which
tells the compiler that he knows that a actually points to a B,
and that the compiler should take his word for it, and not
check.
Probably something like: B* b = dynamic_cast<B*>(a);
Exactly. Generally speaking, it's best to use dynamic_cast when
navigating within a hierarchy, and static_cast when converting
between numeric types (although frankly, I've really nothing
against the old C style casts there). And for the most part,
anything which requires reinterpret_cast (or a static_cast's
with a void* in them somewhere) or a const_cast is suspect.
And third, it doesn't crash, and actually works perfectly
fine, because the second() method does not use any instance
data of a/b.
It's undefined behavior, and anything can happen. Including
that the code appears to work.
The "this" 'keyword' is just pushed on the stack as a hidden
argument,
Again, this is unspecified (and certainly not the case with the
compilers I use on Sun Sparc).
but since second() does not access 'this', it acts like a
static method.
Or doesn't. It's undefined behavior. What you're describing is
a frequent result of common implementations, but it's nothing he
can count on.
If you would have done this:
class B: public A {
public:
void first();
void second();

int mInstanceData;
};
void B::second() {
cout << "B::second()" << mInstanceData << endl;
}
then the following should crash, yes:
int main() {
A* a = new A;
B* b = (B*)a;
b->second();
return 0;
}
Or not. It's also undefined behavior, and I wouldn't be
surprised if it didn't just output some random value, rather
than crashing.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 29 '08 #5
On Jul 29, 6:42 am, raicuandi <raicua...@gmail.comwrote:
On Jul 29, 12:26 pm, cron...@gmail.com wrote:
[...]
Btw, to continue, this means that nomather what value you have
in the pointer 'b', it would still work. Including NULL.
B* b = (B*)NULL;
b->second(); // works, because B::second does not access any instance
data
Again, undefined behavior. And in this case, I've actually used
a compiler which would crash with this code.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 29 '08 #6
cr*****@gmail.com wrote:
Why doesn't the following throw an exception. It seems like you
should not be able to downcast from A to B since A is not a B.

#include <iostream>

using namespace std;

class A {
public:
virtual void first();
};

class B: public A {
public:
void first();
void second();
};

void A::first() {
cout << "A::first()" << endl;
}

void B::first() {
cout << "B::first()" << endl;
}

void B::second() {
cout << "B::second()" << endl;
}

int main() {
A* a = new A;
B* b = (B*)a;
This shows the danger of using C style casts. Effectively you are not
asking the compiler to do this, you are telling it: "Pointer a
actually points to an object of class B. Trust me, I know what I'm
doing!".

Like others have told you, using a dynamic_cast is asking the compiler
to do the cast, *if possible*.
b->second();
return 0;
}

Bo Persson
Jul 29 '08 #7
In article
<4b**********************************@c65g2000hsa. googlegroups.com>, James
Kanze <ja*********@gmail.comwrote:
...
Generally speaking, it's best to use dynamic_cast when
navigating within a hierarchy, and static_cast when converting
between numeric types (although frankly, I've really nothing
against the old C style casts there). And for the most part,
anything which requires reinterpret_cast (or a static_cast's
with a void* in them somewhere) or a const_cast is suspect.
The problem with a C-style cast is that it can do a reinterpret_cast too
easily. (int) foo could be a reinterpret_cast if foo is unexpectedly a
pointer type. Unfortunately, even a functional-style cast is no better;
int (foo) will behave exactly the same. I'd really like a compiler which
warned when a functional-style cast was doing anything beyond an implicit
conversion.
Jul 29 '08 #8
On Jul 29, 6:14*pm, "Bo Persson" <b...@gmb.dkwrote:
cron...@gmail.com wrote:
Why doesn't the following throw an exception. *It seems like you
should not be able to downcast from A to B since A is not a B.
#include <iostream>
using namespace std;
class A {
public:
* virtual void first();
};
class B: public A {
public:
* void first();
* void second();
};
void A::first() {
* cout << "A::first()" << endl;
}
void B::first() {
* cout << "B::first()" << endl;
}
void B::second() {
* cout << "B::second()" << endl;
}
int main() {
* A* a = new A;
* B* b = (B*)a;

This shows the danger of using C style casts. Effectively you are not
asking the compiler to do this, you are telling it: "Pointer a
actually points to an object of class B. Trust me, I know what I'm
doing!".

Like others have told you, using a dynamic_cast is asking the compiler
to do the cast, *if possible*.
* b->second();
* return 0;
}

Bo Persson
The REAL problem with C style cast is that it requires the programmer
to *think*, and apply the mythical powers of "common sense" when
designing software, instead of relying on obscure things to fill that
gap. Like RTTI.
Trust me, I know what I'm doing!
I thought that's the whole point of writing C/C++ :) Or else why not
use Java, where it takes a screenful of code to read a line from a
file. But hey, you're safe there. Every other line is an exception
handler, to protect you from your own code. Brilliant!

Cheers!
-- raicuandi
Jul 30 '08 #9
On Jul 29, 12:38 pm, blargg....@gishpuppy.com (blargg) wrote:
In article
<4b1312db-e94b-4083-a622-4f508e33a...@c65g2000hsa.googlegroups.com>, James
Kanze <james.ka...@gmail.comwrote:
...
Generally speaking, it's best to use dynamic_cast when
navigating within a hierarchy, and static_cast when converting
between numeric types (although frankly, I've really nothing
against the old C style casts there). And for the most part,
anything which requires reinterpret_cast (or a static_cast's
with a void* in them somewhere) or a const_cast is suspect.
The problem with a C-style cast is that it can do a
reinterpret_cast too easily.
Yes. The problem is that you can't distinguish between the two.
But of course, as long as only numeric types are involved, the
only legal new style cast is static_cast, so it doesn't matter.
(int) foo could be a reinterpret_cast if foo is unexpectedly a
pointer type.
If you don't know whether foo is a pointer or an integral type,
your code isn't going to work. Regardless of the type of cast.
Unfortunately, even a functional-style cast is no better; int
(foo) will behave exactly the same. I'd really like a compiler
which warned when a functional-style cast was doing anything
beyond an implicit conversion.
You mean anytime you use one to create a temporary object, like
MyClass()?

Probably the reason why I often use C style casts for numeric
types is that I always put the parentheses around the argument,
so they really look about the same as a functional style cast
(e.g. "(unsigned int)( whatever )", as compared to "MyClass(
whatever )"). And while the standard considers all of these to
be casts, I (and I think many others) think of them more as the
creation of a temporary object: I find it hard to think of
"MyClass()" or "MyClass( a, b, c )" as a type conversion,
regardless of what the standard says. And in many cases, I
think of something like "(double)( someInt )" in the same way.
In the case of double, I could actually write "double(
someInt )", but this won't work if the typename is more
complex, e.g. unsigned char, or long long (probably the two most
frequent cases in my code).

What I'd like is for the compiler to warn anytime I use anything
but a new style cast, but only if a pointer or reference is
involved (on one side or the other).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 30 '08 #10

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

Similar topics

2
by: Steve Schlesinger | last post by:
In the following code I do a forced downcast of an A object to its derivative B If I declare all member variables in A and only add member functions in B, will this always work? The test...
2
by: Chester | last post by:
Is it possible to new an object A, downcast it to B, and store B in a vector? I'm having problem with the following code: B is a derived class of A Blist.push_back( new B() ); Blist.push_back(...
8
by: | last post by:
#include <iostream> using namespace std; class Base { public: Base() {} ~Base() {} };
4
by: jayesah | last post by:
Hi All, I have following code. Anyone can please tell me how object of type class A is converted to Class B ? #include <iostream.h> class A { public: void operator=(int i){a=i;}
3
by: alebcn75 | last post by:
Hello, I'm having a design issue that I can't solve. I'm getting from a network a stream of data, which is a http message (my program is neither a client or server, it just catches messages over...
0
by: JessicaLampe | last post by:
Hello @all, I retrieve the active Excel workbooks by enumerating the ROT table directly. Now I search a way to get the Excel application instance of these workbooks. I don't know how to cast it...
4
by: neisan | last post by:
Hi, I created a vector like that" typedef std::vector<Client*> Clients" and declared a vector "Clients clients". I specialized the Client class to SpecialClient, so I have: class Client ...
10
by: Dom Jackson | last post by:
I have a program which crashes when: 1 - I use static_cast to turn a base type pointer into a pointer to a derived type 2 - I use this new pointer to call a function in an object of the...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
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
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...

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.