|
From: Ioannis V. <no...@ya...> - 2001-10-20 16:22:49
|
Strange effect. Consider the code:=20
=20
#include <iostream>
=20
class A
{
public:
void test() { std::cout<<"A!\n"; }
};
=20
class C: public A
{
public:
void test() { std::cout<<"C!\n"; }
};
=20
=20
=20
int main()
{
using namespace std;
=20
A a;
=20
C *cp=3Dstatic_cast<C *>(&a);
=20
cp->test();
=20
}
=20
=20
It produces
=20
C:\c>temp
C!
=20
Isn't this wrong? I expected either a GPF or garbage, or even "A!" but
not "C!".
=20
=20
Ioannis
=20
* Ioannis Vranos
* Programming pages: http://www.noicys.f2s.com
<http://www.noicys.f2s.com/>=20
* Alternative URL: http://run.to/noicys
=20
|
|
From: Jason H. <jas...@bt...> - 2001-10-20 16:49:16
|
MessageAFAICT a static_cast will always be able to cast a pointer from a =
base into a derived type without checking if it's OK to do so as =
dynamic_cast would.
Also of note is that the methods are not virtual, so the test in C would =
hide the test in A. And as neither objects contains any data then there =
is no real difference between them. If I had more time I would try out a =
few things, like making the methods virtual and adding variables to the =
objects, i.e. private: int data; initialised differently in each object, =
with a getter function the same in each class.
When multiple instances of an object is created there is still only one =
method in memory, which is passed a this pointer to the object it is =
operating on. So in the case of this example there are two methods =
defined, and when you cast into the C type the compiler directs to the C =
method as opposed to the A method. If you tried to access data that =
existed in C but not A then you would get errors.
I hope I have explained that OK. I'm rushing a little as I'm going out =
in a minute.
Jason.
----- Original Message -----=20
From: Ioannis Vranos=20
To: Dev-C++=20
Sent: Saturday, October 20, 2001 6:24 PM
Subject: [Dev-C++] Strange effect
Strange effect. Consider the code:=20
#include <iostream>
class A
{
public:
void test() { std::cout<<"A!\n"; }
};
class C: public A
{
public:
void test() { std::cout<<"C!\n"; }
};
int main()
{
using namespace std;
=20
A a;
=20
C *cp=3Dstatic_cast<C *>(&a);
=20
cp->test();
}
It produces
C:\c>temp
C!
Isn't this wrong? I expected either a GPF or garbage, or even "A!" but =
not "C!".
Ioannis
* Ioannis Vranos
* Programming pages: http://www.noicys.f2s.com
* Alternative URL: http://run.to/noicys
|
|
From: Ioannis V. <no...@ya...> - 2001-10-20 17:36:41
|
At first, this result comes from both dev-c++ and bcc32. We should not see "C!" even if the member functions were virtual since we have an object A, not C assigned to A * (that's why a dynamic_cast would fail). Also every object has (must have) its own member function so there is not "only one method in memory" as you mention. Yours is the case of *static* member functions. Probably we have here some compiler optimization being confused by casting. This is definately a compiler defect(for both of them). =20 =20 Ioannis =20 * Ioannis Vranos * Programming pages: http://www.noicys.f2s.com <http://www.noicys.f2s.com/>=20 * Alternative URL: http://run.to/noicys -----Original Message----- From: dev...@li... [mailto:dev...@li...] On Behalf Of Jason Hardman Sent: Saturday, October 20, 2001 6:49 PM To: Dev-C++ Subject: Re: [Dev-C++] Strange effect AFAICT a static_cast will always be able to cast a pointer from a base into a derived type without checking if it's OK to do so as dynamic_cast would. =20 Also of note is that the methods are not virtual, so the test in C would hide the test in A. And as neither objects contains any data then there is no real difference between them. If I had more time I would try out a few things, like making the methods virtual and adding variables to the objects, i.e. private: int data; initialised differently in each object, with a getter function the same in each class. =20 When multiple instances of an object is created there is still only one method in memory, which is passed a this pointer to the object it is operating on. So in the case of this example there are two methods defined, and when you cast into the C type the compiler directs to the C method as opposed to the A method. If you tried to access data that existed in C but not A then you would get errors. =20 I hope I have explained that OK. I'm rushing a little as I'm going out in a minute. =20 Jason. ----- Original Message -----=20 From: Ioannis Vranos <mailto:no...@ya...> =20 To: Dev-C++ <mailto:dev...@li...> =20 Sent: Saturday, October 20, 2001 6:24 PM Subject: [Dev-C++] Strange effect Strange effect. Consider the code:=20 =20 #include <iostream> =20 class A { public: void test() { std::cout<<"A!\n"; } }; =20 class C: public A { public: void test() { std::cout<<"C!\n"; } }; =20 =20 =20 int main() { using namespace std; =20 A a; =20 C *cp=3Dstatic_cast<C *>(&a); =20 cp->test(); =20 } =20 =20 It produces =20 C:\c>temp C! =20 Isn't this wrong? I expected either a GPF or garbage, or even "A!" but not "C!". =20 =20 Ioannis =20 * Ioannis Vranos * Programming pages: http://www.noicys.f2s.com <http://www.noicys.f2s.com/>=20 * Alternative URL: http://run.to/noicys =20 |
|
From: Jason H. <jas...@bt...> - 2001-10-20 23:22:07
|
MessageHi, I'm back now. I've just been to see a great Depeche Mode = concert (WOW!). As I mentioned I was writing the explanation of what I think is really = happening quickly. I'll try again and see if it comes out right. You have two classes one derived from the other, the derived class has a = method that overrides one in the base. In other words two methods with = the same name but different implementations. Now pretend that the two = methods are actually *two* functions which are passed a pointer to a = struct of some sort, which is basically how a method is implemented = (don't complain, it's an analogy). When you turn pointer to the base = type into an pointer to the derived type, even if it isn't a derived = object, then you are telling the compiler that you want to use the = object as a derived type. So when you call a method via that pointer the = compiler thinks that you are really using a derived object and will try = to find the correct function. Because both the functions have the same = name, it will find a "test" function and pass the "this" pointer to that = function that belongs to derived type, even though the "this" really = points to a base object. I hope you are following me so far? I understand the idea in my head but = it's not easy for me to explain properly. Both the functions (methods) = do something, however they don't try to access anything through the = "this" pointer. That means that you won't get any problems like you = would if you tried accessing something that doesn't exist in base, but = is expected of derived. So all that happens is the derived "test" function is called and passed = a pointer it doesn't use. The function is hard coded to print out "C" in = this case. That is the why (AFAICT) what happens, happens. Whether the compiler = should complain I don't know, it depends upon what the standard says = about this case. It's only the fact that the two methods have the same = name that let's this work the way it does. Does all this scan? I am pretty certain that this is what is happening = internally. If C wasn't derived from A and you managed to cast A into C then, in = theory at least, you would get the same result. Note I have not tested = this. I think maybe that static_cast would not allow it to happen, so a = reinterpret_cast would be needed. This is just a thought, and may not be = an actual truth. Regards, Jason. ----- Original Message -----=20 From: Ioannis Vranos=20 To: Dev-C++=20 Sent: Saturday, October 20, 2001 7:38 PM Subject: RE: [Dev-C++] Strange effect At first, this result comes from both dev-c++ and bcc32. We should not = see "C!" even if the member functions were virtual since we have an = object A, not C assigned to A * (that's why a dynamic_cast would fail). = Also every object has (must have) its own member function so there is = not "only one method in memory" as you mention. Yours is the case of = *static* member functions. Probably we have here some compiler = optimization being confused by casting. This is definately a compiler = defect(for both of them). Ioannis * Ioannis Vranos * Programming pages: http://www.noicys.f2s.com * Alternative URL: http://run.to/noicys -----Original Message----- From: dev...@li... = [mailto:dev...@li...] On Behalf Of Jason = Hardman Sent: Saturday, October 20, 2001 6:49 PM To: Dev-C++ Subject: Re: [Dev-C++] Strange effect AFAICT a static_cast will always be able to cast a pointer from a = base into a derived type without checking if it's OK to do so as = dynamic_cast would. Also of note is that the methods are not virtual, so the test in C = would hide the test in A. And as neither objects contains any data then = there is no real difference between them. If I had more time I would try = out a few things, like making the methods virtual and adding variables = to the objects, i.e. private: int data; initialised differently in each = object, with a getter function the same in each class. When multiple instances of an object is created there is still only = one method in memory, which is passed a this pointer to the object it is = operating on. So in the case of this example there are two methods = defined, and when you cast into the C type the compiler directs to the C = method as opposed to the A method. If you tried to access data that = existed in C but not A then you would get errors. I hope I have explained that OK. I'm rushing a little as I'm going = out in a minute. Jason. ----- Original Message -----=20 From: Ioannis Vranos=20 To: Dev-C++=20 Sent: Saturday, October 20, 2001 6:24 PM Subject: [Dev-C++] Strange effect Strange effect. Consider the code:=20 #include <iostream> class A { public: void test() { std::cout<<"A!\n"; } }; class C: public A { public: void test() { std::cout<<"C!\n"; } }; int main() { using namespace std; =20 A a; =20 C *cp=3Dstatic_cast<C *>(&a); =20 cp->test(); } It produces C:\c>temp C! Isn't this wrong? I expected either a GPF or garbage, or even "A!" = but not "C!". Ioannis * Ioannis Vranos * Programming pages: http://www.noicys.f2s.com * Alternative URL: http://run.to/noicys |
|
From: Ioannis V. <no...@ya...> - 2001-10-21 10:20:18
|
Jason, i strongly disagree with you. :) Each object has its *own* member
functions and no external function is passed to them in anyway. That's
why the cost of calling a member function is smaller than the cost of
calling an external function. For accuracy, the compiler should behave
as if this happens. :) Compiler can optimize its way as it likes as far
as it follows this behavior. In our case C class is derived from A, so a
C object contains a A object. Also we have public inheritance which
means that all methods of A are accessible within C if not overided.=20
A C object has bigger size than a A object. Here we have a A object not
a C object. If we could do these kinds of things we could create base
class objects cast them to their derived types and have derived objects
doing the same things having smaller size (=3Dmiracle).
In our case my theory is that this happens: The compiler trying to
produce even smaller size than it would in normal situation, creates
common instances of member functions. Here it gets confused by the
casting and a mess is created.
=20
Proof that this is a compiler defect:
=20
#include <iostream>
=20
class A
{
public:
char a;
void test() { a=3D'A'; }
};
=20
class C: public A
{
public:
char b;
void test() { a=3D'C'; b=3D'D'; }
};
=20
=20
=20
int main()
{
using namespace std;
=20
A a;
=20
C *cp=3Dstatic_cast<C *>(&a);
=20
cp->test();
=20
cout<<"a=3D "<<cp->a<<" b=3D "<<cp->b<<endl;
=20
cout<<"sizeof(A)=3D "<<sizeof(A)<<" sizeof(C)=3D "<<sizeof(C)<<endl;
}
=20
=20
Ioannis
=20
* Ioannis Vranos
* Programming pages: http://www.noicys.f2s.com
<http://www.noicys.f2s.com/>=20
* Alternative URL: http://run.to/noicys
=20
-----Original Message-----
From: dev...@li...
[mailto:dev...@li...] On Behalf Of Jason
Hardman
Sent: Sunday, October 21, 2001 1:20 AM
To: Dev-C++
Subject: Re: [Dev-C++] Strange effect
Hi, I'm back now. I've just been to see a great Depeche Mode concert
(WOW!).
=20
As I mentioned I was writing the explanation of what I think is really
happening quickly. I'll try again and see if it comes out right.
=20
You have two classes one derived from the other, the derived class has a
method that overrides one in the base. In other words two methods with
the same name but different implementations. Now pretend that the two
methods are actually *two* functions which are passed a pointer to a
struct of some sort, which is basically how a method is implemented
(don't complain, it's an analogy). When you turn pointer to the base
type into an pointer to the derived type, even if it isn't a derived
object, then you are telling the compiler that you want to use the
object as a derived type. So when you call a method via that pointer the
compiler thinks that you are really using a derived object and will try
to find the correct function. Because both the functions have the same
name, it will find a "test" function and pass the "this" pointer to that
function that belongs to derived type, even though the "this" really
points to a base object.
=20
I hope you are following me so far? I understand the idea in my head but
it's not easy for me to explain properly. Both the functions (methods)
do something, however they don't try to access anything through the
"this" pointer. That means that you won't get any problems like you
would if you tried accessing something that doesn't exist in base, but
is expected of derived.
=20
So all that happens is the derived "test" function is called and passed
a pointer it doesn't use. The function is hard coded to print out "C" in
this case.
=20
That is the why (AFAICT) what happens, happens. Whether the compiler
should complain I don't know, it depends upon what the standard says
about this case. It's only the fact that the two methods have the same
name that let's this work the way it does.
=20
Does all this scan? I am pretty certain that this is what is happening
internally.
=20
If C wasn't derived from A and you managed to cast A into C then, in
theory at least, you would get the same result. Note I have not tested
this. I think maybe that static_cast would not allow it to happen, so a
reinterpret_cast would be needed. This is just a thought, and may not be
an actual truth.
=20
Regards, Jason.
|