Topic: backward virtual function call
Author: hitz@sim5.csi.uottawa.ca (Martin Hitz)
Date: 30 Apr 91 02:40:10 GMT Raw View
I wonder if the following is guaranteed to print 1:
#include <stream.h>
struct X {
virtual f() { return 1; }
};
struct Y : X {
f() { return 2; }
};
main()
{
X x;
Y * y = (Y *) &x;
cout << y->f();
}
The ARM explains the usual case, that a call of f() for an object of
class Y invokes Y::f(), even if it is called via a pointer to X,
but I couldn't find anything about the above case. Zortech and g++
both yield 1 for this example. Is this considered to be the standard
behaviour?
Martin Hitz (hitz@csi.uottawa.ca)
Author: wmm@world.std.com (William M Miller)
Date: 30 Apr 91 14:03:13 GMT Raw View
hitz@sim5.csi.uottawa.ca (Martin Hitz) writes:
> struct X {
> virtual f() { return 1; }
> };
> struct Y : X {
> f() { return 2; }
> };
>
> main()
> {
> X x;
> Y * y = (Y *) &x;
> cout << y->f();
> }
>
> The ARM explains the usual case, that a call of f() for an object of
> class Y invokes Y::f(), even if it is called via a pointer to X,
> but I couldn't find anything about the above case.
That's because it's an error. See section 5.4 of E&S: "Such a cast from a
base to a derived class assumes that the object of the base class is a
sub-object of an object of the derived class; the resulting pointer points
to the enclosing object of the derived class. If the object of the base
class is not a sub-object of an object of the derived class, the cast may
cause an exception." In other words, the behavior is undefined, and an
implementation under which the program printed -356, or dumped core, or
erased your disk would be perfectly legitimate.
-- William M. Miller, Glockenspiel, Ltd.
wmm@world.std.com
Author: ark@alice.att.com (Andrew Koenig)
Date: 30 Apr 91 21:15:21 GMT Raw View
In article <1991Apr30.024010.4331@csi.uottawa.ca> hitz@sim5.csi.uottawa.ca (Martin Hitz) writes:
> #include <stream.h>
> struct X {
> virtual f() { return 1; }
> };
> struct Y : X {
> f() { return 2; }
> };
> main()
> {
> X x;
> Y * y = (Y *) &x;
> cout << y->f();
> }
The effects of things like this are undefined.
In this particular example, I expect that many implementations
will print 2, but the assignment
Y * y = (Y *) &x;
is well-defined only if &x points at an object of class Y --
which, of course, it does not.
--
--Andrew Koenig
ark@europa.att.com
Author: jimad@microsoft.UUCP (Jim ADCOCK)
Date: 6 May 91 19:12:04 GMT Raw View
In article <1991Apr30.024010.4331@csi.uottawa.ca> hitz@sim5.csi.uottawa.ca (Martin Hitz) writes:
|I wonder if the following is guaranteed to print 1:
|
|#include <stream.h>
|struct X {
| virtual f() { return 1; }
|};
|struct Y : X {
| f() { return 2; }
|};
|
|main()
|{
| X x;
| Y * y = (Y *) &x;
| cout << y->f();
|}
|
|The ARM explains the usual case, that a call of f() for an object of
|class Y invokes Y::f(), even if it is called via a pointer to X,
|but I couldn't find anything about the above case. Zortech and g++
|both yield 1 for this example. Is this considered to be the standard
|behaviour?
What would a C++ compiler then do with the following?
[All that I'm aware of act in an ill-defined manner, which is expected
since the ARM prohibits such erroneous down-casts. Your example just
happens to work on most C++ compilers]
extern "C" int printf(const char*, ...);
class A
{
private: virtual void illegalToAccess()
{ printf("erroneous access of A private method\n"); }
public: virtual void print() { printf("A\n"); }
};
class B
{
public: virtual void print() { printf("B\n"); }
private: virtual void illegalToAccess()
{ printf("erroneous access of B private method\n"); }
};
class AB: public A, public B
{
public: virtual void print() { printf("AB\n"); }
};
main()
{
A aA;
B aB;
A* a = &aA;
((AB*)a)->print();
B* b = &aB;
((AB*)b)->print();
return 0;
}