473,386 Members | 1,694 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,386 software developers and data experts.

Bogus cast from class to totally unrelated class works - why?

Hello All,

I did try searching the archives, but the topics seemed to be mostly
about base
and derived classes.

I have reached Chapter 8 in Bruce Eckel's "Thinking in C++ 2nd Edition
Vol. 1".
Question 28 says:

"Create a class called bird that can fly( ) and a class rock that
can't. Create
a rock object, take its address, and assign that to a void*. Now take
the void*,
assign it to a bird* (you'll have to use a cast), and call fly( )
through that
pointer. Is it clear why C's permission to openly assign via a void*
(without a cast) is a "hole" in the language, which couldn't be
propagated
into C++?"

I came up with:

#include <iostream>
using namespace std;

class Bird{
public:
void fly(){ cout << "Flying..." << endl; }
};

class Rock{
double d;
};

int main()
{
Rock r;
void *v = &r;
Bird *pb = reinterpret_cast<Bird*>(v);
pb->fly();
return 0;
}

This compiled and linked without warnings, as I expected. I understand
why
you should not be allowed to convert a Rock to a Bird (unless you
really, really
want to very badly).

What I did *not* expect was that it would run, but it did. Why don't
I get
a run-time error when I call fly() in my Rock masquerading as a Bird?

I tried it with gcc 3.4.2 (MingW Windows port) and 4.1.1
(http://oss.netfarm.it/mplayer-win32.php) and it worked in both cases.
I am on Windows XP SP2.

May 13 '07 #1
5 1876
On 13 May, 19:15, johnbrown...@hotmail.com wrote:
Hello All,

I did try searching the archives, but the topics seemed to be mostly
about base
and derived classes.

I have reached Chapter 8 in Bruce Eckel's "Thinking in C++ 2nd Edition
Vol. 1".
Question 28 says:

"Create a class called bird that can fly( ) and a class rock that
can't. Create
a rock object, take its address, and assign that to a void*. Now take
the void*,
assign it to a bird* (you'll have to use a cast), and call fly( )
through that
pointer. Is it clear why C's permission to openly assign via a void*
(without a cast) is a "hole" in the language, which couldn't be
propagated
into C++?"

I came up with:

#include <iostream>
using namespace std;

class Bird{
public:
void fly(){ cout << "Flying..." << endl; }

};

class Rock{
double d;

};

int main()
{
Rock r;
void *v = &r;
Bird *pb = reinterpret_cast<Bird*>(v);
pb->fly();
return 0;

}

This compiled and linked without warnings, as I expected. I understand
why
you should not be allowed to convert a Rock to a Bird (unless you
really, really
want to very badly).

What I did *not* expect was that it would run, but it did. Why don't
I get
a run-time error when I call fly() in my Rock masquerading as a Bird?

I tried it with gcc 3.4.2 (MingW Windows port) and 4.1.1
(http://oss.netfarm.it/mplayer-win32.php) and it worked in both cases.
I am on Windows XP SP2.
Well the behaviour is undefined so the compiler is allowed to do
anything it wants and from a language definition point of view no
outcome is more or less valid than any other. But what is probably
happening is:

fly() is a member function of Bird and so your compiler creates code
exactly as it would for a normal function, except it inserts an extra
parameter of type Bird*. This extra parameter is the implied this
pointer that every (non-static) member function of any class has but
that does not appear explicitly in the parameter list. Now, in your
code, the Bird* this pointer inside fly() actually points to a Rock
and so any attempt to use or dereference the pointer isn't going to
work. But none of the code in your fly() function actually uses the
this pointer - no other member functions of Bird are called and no
member data is touched. Try changing the definition of Bird as below
and you might see something more obviously strange. Watch out for
nasal demons.

class Bird{
public:
Bird() : wbpm(42) {}
void fly()
{
cout << "Flying at " << this->wbpm << " wing beats per
minute" << endl;
}
private:
int wbpm;
};

Gavin Deane

May 13 '07 #2
On May 13, 2:15 pm, johnbrown...@hotmail.com wrote:
Hello All,

I did try searching the archives, but the topics seemed to be mostly
about base
and derived classes.

I have reached Chapter 8 in Bruce Eckel's "Thinking in C++ 2nd Edition
Vol. 1".
Question 28 says:

"Create a class called bird that can fly( ) and a class rock that
can't. Create
a rock object, take its address, and assign that to a void*. Now take
the void*,
assign it to a bird* (you'll have to use a cast), and call fly( )
through that
pointer. Is it clear why C's permission to openly assign via a void*
(without a cast) is a "hole" in the language, which couldn't be
propagated
into C++?"

I came up with:

#include <iostream>
using namespace std;

class Bird{
public:
void fly(){ cout << "Flying..." << endl; }

};

class Rock{
double d;

};

int main()
{
Rock r;
void *v = &r;
Bird *pb = reinterpret_cast<Bird*>(v);
pb->fly();
return 0;

}

This compiled and linked without warnings, as I expected. I understand
why
you should not be allowed to convert a Rock to a Bird (unless you
really, really
want to very badly).
You aren't converting a Rock to a bird, you are 'reinterpreting' a
Rock* to a void* and that to a Bird*.
Converting a pointer converts the pointer, not its pointee.
Did you not read the warnings about using reinterpret_cast?
An old type cast might very well apply a static_cast, a dynamic_cast
or a reinterpret_cast.
You had no control over which was employed. Now you do.

int main()
{
Rock r;
Bird *pb = static_cast<Bird*>(&r); // invalid cast
pb->fly();
return 0;
}

Again, its the pointer being cast, not the object. That Rock is still
a Rock regardless of which type cast you apply on the ptr. I think you
are trying to bite more than you can chew here.
>
What I did *not* expect was that it would run, but it did. Why don't
I get
a run-time error when I call fly() in my Rock masquerading as a Bird?
Because its not a Rock* anymore. Unfortunately, the fly() member
function is not accessing the object in any way, which would generate
an error.
Classic example:

#include <iostream>

class Rock
{
double d;
public:
Rock( double d_ ) : d( d_ )
{ }
double get
() const
{
return d;
}
void foo()
{
std::cout << "Rock::foo()";
}
};

int main()
{
Rock * p;
p->foo(); // no error
p->get(); // seg fault
}

Why, cause there is no Rock object to access. All you have is an
unitialized pointer.
>
I tried it with gcc 3.4.2 (MingW Windows port) and 4.1.1
(http://oss.netfarm.it/mplayer-win32.php) and it worked in both cases.
I am on Windows XP SP2.

May 13 '07 #3
On May 13, 1:47 pm, Gavin Deane <deane_ga...@hotmail.comwrote:
>
... Now, in your
code, the Bird* this pointer inside fly() actually points to a Rock
and so any attempt to use or dereference the pointer isn't going to
work. But none of the code in your fly() function actually uses the
this pointer - no other member functions of Bird are called and no
member data is touched. Try changing the definition of Bird as below
and you might see something more obviously strange. Watch out for
nasal demons.
<cut>

I see. I now get:
Flying at 2009312941 wing beats per minute

I was still expecting something more dramatic than that, but it will
do. Thanks.

May 13 '07 #4
On May 13, 2:12 pm, Salt_Peter <pj_h...@yahoo.comwrote:
>
You aren't converting a Rock to a bird, you are 'reinterpreting' a
Rock* to a void* and that to a Bird*.
Converting a pointer converts the pointer, not its pointee.
I understand. My language was imprecise.
Did you not read the warnings about using reinterpret_cast?
Most certainly.
>
Again, its the pointer being cast, not the object. That Rock is still
a Rock regardless of which type cast you apply on the ptr.
I may be a newbie, but I am not *that* new. I would like to take this
opportunity to remind you of my post's subject line, which is:
*BOGUS CAST ... WORKS - WHY?* I know that my Rock is still
a Rock. I just wanted to know why my Rock did not sink like a
stone, as a proper Rock should have.

I think you
are trying to bite more than you can chew here.
I am doing nothing of the kind. I am doing an exercise from a
textbook, the entire point of which is to show:

1) what can happen when you perform bogus casts, and
2) that C allows assignments to and/or from void *
without a cast, while C++ does not.

If you had bothered to read my post, you would have seen that.
Then again, you didn't even read the subject line. No matter
how anxious you are to attack hapless newbies, you should
at least read the post first.
>
What I did *not* expect was that it would run, but it did. Why don't
I get
a run-time error when I call fly() in my Rock masquerading as a Bird?

Because its not a Rock* anymore. Unfortunately, the fly() member
function is not accessing the object in any way, which would generate
an error.
Which is the useful answer to my query.Thank you.
Classic example:
<Classic example cut>
It crashes at run-time. Now that's more like it.

May 13 '07 #5
On May 14, 6:15 am, johnbrown...@hotmail.com wrote:
What I did *not* expect was that it would run, but it did. Why don't
I get a run-time error when I call fly() in my Rock masquerading as a Bird?
Your expectation is wrong. When you write code that
is compilable but has bogus effects, anything could
happen. Maybe you will get a runtime error but maybe
not. Often it *appears* to work normally, as in your
example, but then fails just when you have to do a
demonstration of your code.

May 13 '07 #6

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

Similar topics

4
by: Clint Hill | last post by:
I am working on a project that I would like to have some extensibility for later. So with this I am using interfaces to pass objects to derived classes. However I am running into a situation where...
6
by: Jordi Vilar | last post by:
Hi All, Is there a way to dynamic_cast a pointer to a type defined by a type_info*? something like: type_info *info_of_type_to_cast = typeid(type_to_cast); type_to_cast *casted =...
2
by: Abhijit Bhadra | last post by:
Hi , I was trying to build my project in VC with latest Service Packs but got this error . C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE\atlconv.h(125) : error C2440: 'return' :...
7
by: VPaul | last post by:
I hope I am posting to the correct group for assistance. Please advise me if there is another group I should go to. I am new to this, so I apologize if I don't explain this very well. I do...
5
by: Jon | last post by:
I am constantly getting reports in my task list like these: * 'someObjectName" is not a member of 'someOtherObjectName' * Handles clause requires a WithEvents variable. * Name 'someName' is not...
8
by: Asfand Yar Qazi | last post by:
Hi, I have the following header file in my 'everything useful I think of in one place' library: ============= BEGIN CODE SNIPPET =========== /** All classes that derive from this obtain a...
18
by: mark | last post by:
class SORef {...}; class SelectedFORef : public SORef {...}; SOFORef SOCastToSOF(SORef sor) { SelectedFORef sof=nil; sof=dynamic_cast<SelectedFORef>(sor); return sof; };
14
by: andreyvul | last post by:
g++ says a reinterpret cast from void* is disallowed; however, all I'm trying to do is de-capsulate a void* argument that holds the pointer to a class (and static_cast forces cast constructor) any...
7
by: Icario | last post by:
I have an error when i compile this: class A { public: void f(A&) {} }; class B: public A { public: void f(B&) {}
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: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
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
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
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...

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.