Topic: this and virtual functions
Author: Alan Griffiths <aGriffiths@ma.ccngroup.com>
Date: 1996/08/29 Raw View
In article: <502hdl$p2t@engnews1.Eng.Sun.COM> dvv@newsreader.sprintlink.net (Dima Volodin) writes:
>
> What should this program print (and why) and what does it print when
> compiled with your favourite compiler?
Class C
Class D
I don't have access to a compiler that gets this wrong!
(I've reformmated quoted code to mimimise quoted text)
> #include <iostream.h>
>
> static void f (void *p) { ff (p); }
> static void ff (void *p) { ((C *)p)->run (); }
>
> class C {
> public:
> C () { f (this); }
^---------- At this point "this" is a C (D doesn't exist)
> void fff () { f (this); }
^--- "this" is a D (D has been constructed)
> virtual void run () { cout << "Class C\n"; }
> };
>
>
>
> class D : public C {
> public:
> void run () { cout << "Class D\n"; }
> };
>
> int main() {
> D d;
>
> d.fff ();
> };
Change the definition of C to:
class C {
public:
C() : i(f(this),0) { f(this); }
void fff () { f (this); }
virtual void run () { cout << "Class C\n"; }
private:
int i;
};
And there is at least one compiler (MSVC) that get it wrong and
doesn't output:
Class C
Class C
Class D
the compiler crashes:
D:\picasso\testmsvc\main.cpp(8) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'd:\vc410\src\P2\main.c', line 413)
__
Alan Griffiths | Also editor of: The ISDF Newsletter
Senior Systems Consultant, | (An Association of C and C++ Users publication)
CCN Group Limited. | (ISDF editor : isdf@octopull.demon.co.uk)
(agriffiths@ma.ccngroup.com) | (For ACCU see : http://bach.cis.temple.edu/accu)
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 1996/08/29 Raw View
In article <502hdl$p2t@engnews1.Eng.Sun.COM>
dvv@newsreader.sprintlink.net (Dima Volodin) writes:
|> What should this program print (and why) and what does it print when
|> compiled with your favourite compiler?
|> #include <iostream.h>
|> static void f (void *p);
|> static void ff (void *p);
|> class C {
|> public:
|> C () {
|> f (this);
|> };
|> void fff () {
|> f (this);
|> };
|> virtual void run () {
|> cout << "Class C\n";
|> };
|> };
|> static void f (void *p) {
|> ff (p);
|> };
|> static void ff (void *p) {
|> ((C *)p)->run ();
|> };
|> class D : public C {
|> public:
|> void run () {
|> cout << "Class D\n";
|> };
|> };
|> main()
|> {
|> D d;
|> d.fff ();
|> };
The results should be two lines:
Class C
Class D
All of the compilers I have access to (Cfront, Sun CC, g++) agree.
The reasoning is simple. All of the calls to ff go through f, and all
of the calls to f are in class C, with the parameter this. Within class
C, this has type C*, and ff casts the void* back to a C*, so the
resulting pointer is still valid.
Within the constructor of C, the object has type C, and so the virtual
function call resolves to C::run. Once the object has been constructed,
it has a dynamic type D, so the virtual function call resolves to
D::run.
What was your question? This all seems pretty clear in the standard,
and doesn't involve anything that wasn't already present in the ARM.
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, tudes et r alisations en logiciel orient objet --
-- A la recherche d'une activit dans une region francophone
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Chelly Green <chelly@eden.com>
Date: 1996/08/29 Raw View
From: Chelly Green <chelly@eden.com>
Newsgroups: comp.std.c++
Subject: Re: this and virtual functions
Date: Thu, 29 Aug 1996 07:14:36 -0600
Organization: -
Lines: 50
Message-ID: <322597BC.39E5@eden.com>
References: <502hdl$p2t@engnews1.Eng.Sun.COM>
Reply-To: chelly@eden.com
NNTP-Posting-Host: net-1-037.austin.eden.com
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: Mozilla 2.01 (Macintosh; I; PPC)
Dima Volodin wrote:
>
> What should this program print (and why)
Absoluelty anything (it may even cause the destruction of the
entire universe!)
Why? Because converting a pointer-to-T to a void*, and then casting
to pointer-to-X (where X and T are different types) is not portable.
(actually, it's probably implementation-defined, not undefined
(I'm too lazy to look it up right now), so it couldn't destroy the
universe. Now if it were undefined, well then... :-)
> and what does it print when compiled with your favourite compiler?
I imagine it may work if there is no pointer adjustment between a
C* and a D*. But I wouldn't count on it.
Of course, the example could have been coded a little more simply:
#include <iostream.h>
struct C { virtual void f() { cout << "C"; } };
struct D : C { void f() { cout << "D"; } };
int main()
{
D d;
((C*) (void*) &d)->f();
return 0;
}
Demonstrates the same idea.
If that works just like doing d.f(), try replacing the base classes
of D with this:
struct X { int i; };
struct D : X, C { // ...
> [ Mod Note: articles consisting just of compiler output are not
> appropriate for this newsgroup. It's OK to mention that compiler
> X gets it wrong and compiler Y gets it right, but let's keep the
> focus on the language definition and correct behavior. -sdc ]
...
--
Chelly Green | mailto:chelly@eden.com | http://www.eden.com/~chelly
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Chelly Green <chelly@eden.com>
Date: 1996/08/30 Raw View
> Dima Volodin wrote:
> >
> > What should this program print (and why)
>
> Absoluelty anything (it may even cause the destruction of the
> entire universe!)
>
> Why? Because converting a pointer-to-T to a void*, and then casting
> to pointer-to-X (where X and T are different types) is not portable.
(actually, probably *using* this new value, other than casting it
back to the original, is not portable).
> > and what does it print when compiled with your favourite compiler?
>
> I imagine it may work if there is no pointer adjustment between a
> C* and a D*. But I wouldn't count on it.
Andrew Gierth politely pointed out to me the only conversion was from
C* to void* back to C*, so it was completely OK. I had thought the
poster was converting D* to void*, then to C*. Who knows, maybe
the poster *was* wondering about that (carefully re-reading the
confusing code revealed nothing out of the ordinary).
I'll try not to make these silly little mistakes again, honest!
...
--
Chelly Green | mailto:chelly@eden.com | http://www.eden.com/~chelly
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Andrew Gierth <andrewg@microlise.co.uk>
Date: 1996/08/30 Raw View
>>>>> "Chelly" == Chelly Green <chelly@eden.com> writes:
> Dima Volodin wrote:
>> What should this program print (and why)
Chelly> Absoluelty anything (it may even cause the destruction of the
Chelly> entire universe!)
Chelly> Why? Because converting a pointer-to-T to a void*, and then
Chelly> casting to pointer-to-X (where X and T are different types)
Chelly> is not portable. (actually, it's probably
Chelly> implementation-defined, not undefined (I'm too lazy to look
Chelly> it up right now), so it couldn't destroy the universe. Now if
Chelly> it were undefined, well then... :-)
No, you missed the mark a fraction here; the pointer conversions in the
posted code were from C* to void* to C*, which is perfectly legal. The
fact that the C* was sometimes pointing to an object whose dynamic type
was D is irrelevent.
--
Andrew Gierth (andrewg@microlise.co.uk)
Unsolicited email (technical questions or otherwise) is NOT welcome.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 1996/08/30 Raw View
In article <32259C25.CF1@eden.com> Chelly Green <chelly@eden.com>
writes:
|> Dima Volodin wrote:
|> >
|> > What should this program print (and why)
|> Absoluelty anything (it may even cause the destruction of the
|> entire universe!)
|> Why? Because converting a pointer-to-T to a void*, and then casting
|> to pointer-to-X (where X and T are different types) is not portable.
|> (actually, it's probably implementation-defined, not undefined
|> (I'm too lazy to look it up right now), so it couldn't destroy the
|> universe. Now if it were undefined, well then... :-)
This is correct, but the posted program never did this. It converted a
pointer-to-C to a void* when calling `f' (all calls to `f' were from
member functions of class C), then cast it back to pointer-to-C in `ff'.
While as presented, the program was horribly dangerous, since you could
potentially call `f' with a pointer to just about anything, I presume
that this is due to it having been distilled to just show the
interesting parts. In any case, nowhere in the program was there a call
to `f' with anything other than a pointer-to-C. (I verified this
several times, because, like you, I suspected undefined behavior.
Usually, when someone asks a question like this, it is because he has
two compilers which do different things, and 95% of the time, it is due
to undefined behavior.)
|> > and what does it print when compiled with your favourite compiler?
|> I imagine it may work if there is no pointer adjustment between a
|> C* and a D*. But I wouldn't count on it.
It had better print:
Class C
Class D
Otherwise, the compiler is broken.
|> Of course, the example could have been coded a little more simply:
|> #include <iostream.h>
|> struct C { virtual void f() { cout << "C"; } };
|> struct D : C { void f() { cout << "D"; } };
|> int main()
|> {
|> D d;
|> ((C*) (void*) &d)->f();
|> return 0;
|> }
|> Demonstrates the same idea.
Not at all. Note that the original program calls a member function of C
in order to call the function which does the cast to void, and always
calls this function with the this pointer. Within a member function of
C, the this pointer is always a pointer-to-C. (It may be a pointer to
the C in D, but this doesn't matter. It still points to the C.)
|> If that works just like doing d.f(), try replacing the base classes
|> of D with this:
|> struct X { int i; };
|> struct D : X, C { // ...
All of what you are saying is true. It just doesn't apply to the
program that was posted. The posted program works fine, even with the
above changes (as it should do).
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, tudes et r alisations en logiciel orient objet --
-- A la recherche d'une activit dans une region francophone
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: dvv@newsreader.sprintlink.net (Dima Volodin)
Date: 1996/08/28 Raw View
What should this program print (and why) and what does it print when
compiled with your favourite compiler?
[ Mod Note: articles consisting just of compiler output are not
appropriate for this newsgroup. It's OK to mention that compiler
X gets it wrong and compiler Y gets it right, but let's keep the
focus on the language definition and correct behavior. -sdc ]
#include <iostream.h>
static void f (void *p);
static void ff (void *p);
class C {
public:
C () {
f (this);
};
void fff () {
f (this);
};
virtual void run () {
cout << "Class C\n";
};
};
static void f (void *p) {
ff (p);
};
static void ff (void *p) {
((C *)p)->run ();
};
class D : public C {
public:
void run () {
cout << "Class D\n";
};
};
main()
{
D d;
d.fff ();
};
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]