Why the output for this small pgm so?

N

nas

Consider this example program which i hav taken from some site

#include <iostream>
using namespace std;

class Base1 {
public:
virtual void f() { }
};

class Base2 {
public:
virtual void f() { }
};

class Base3 {
public:
virtual void f() { }
};

class Drive : public Base1, public Base2, public Base3 {
};

// any non zero value because multiply zero with any no is zero
#define SOME_VALUE 1

int main() {
cout << (DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
cout << (DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
cout << (DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
return 0;
}

Output of this prgram is:
0
4
8


Can any one tell me How does
(DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE
(DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE
(DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE

Gives you 0,4,8?

More surprisingly if i define SOME_VALUE to 0, that is if i do
#define SOME_VALUE 0
I get output as 0,0,0 itself! if i assign ANY non zero number to
SOME_VALUE then i wil get the first answer which is 0,4,8.

Can any one exaplain me how?
 
N

Neelesh Bodas

Consider this example program which i hav taken from some site

#include <iostream>
using namespace std;

class Base1 {
public:
virtual void f() { }

};

class Base2 {
public:
virtual void f() { }

};

class Base3 {
public:
virtual void f() { }

};

class Drive : public Base1, public Base2, public Base3 {

};

// any non zero value because multiply zero with any no is zero
#define SOME_VALUE 1

int main() {
cout << (DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
cout << (DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
cout << (DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
return 0;

}

Output of this prgram is:
0
4
8

Can any one tell me How does
(DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE
(DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE
(DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE

Gives you 0,4,8?

The allocation of base classes within the derived class, the
implementation of virtual functions,the alignment issues are all
implementation dependent.

-N
 
N

nas

The allocation of base classes within the derived class, the
implementation of virtual functions,the alignment issues are all
implementation dependent.

-N- Hide quoted text -

- Show quoted text -

I compiled above program in Visual Studio 2005
 
S

Stuart Redmann

Neelesh said:
The allocation of base classes within the derived class, the
implementation of virtual functions,the alignment issues are all
implementation dependent.

See http://www.phpcompiler.org/doc/virtualinheritance.html for a good
explanation of these compiler specific implementation details (I know no C++
compiler that uses an implementation that really differs at more than minor
pointers from the design explained there).

As for the results of your application for the case where SOME_VALUE has been
set to 1: The value zero is used by MS for the representation of the Null
pointer. If you static_cast the Null-pointer to a pointer of base classes,
you'll receive the Null-pointer again (the Null-pointer is the only pointer that
differs in that regard from any other pointer).

Regards,
Stuart
 
N

nas

Seehttp://www.phpcompiler.org/doc/virtualinheritance.htmlfor a good
explanation of these compiler specific implementation details (I know no C++
compiler that uses an implementation that really differs at more than minor
pointers from the design explained there).

As for the results of your application for the case where SOME_VALUE has been
set to 1: The value zero is used by MS for the representation of the Null
pointer. If you static_cast the Null-pointer to a pointer of base classes,
you'll receive the Null-pointer again (the Null-pointer is the only pointer that
differs in that regard from any other pointer).

Regards,
Stuart- Hide quoted text -

- Show quoted text -

Thanks...I think u are right. Thank you again.
But the initially how we got 0,4,8 ??? What might be the reson for
this?
 
J

James Kanze

Consider this example program which i hav taken from some site
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f() { }
};
class Base2 {
public:
virtual void f() { }
};
class Base3 {
public:
virtual void f() { }
};
class Drive : public Base1, public Base2, public Base3 {
};
// any non zero value because multiply zero with any no is zero
#define SOME_VALUE 1
int main() {
cout << (DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
cout << (DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
cout << (DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE <<
endl;
return 0;
}
Output of this prgram is:
0
4
8
Can any one tell me How does
(DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE
(DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE
(DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE
Gives you 0,4,8?

More surprisingly if i define SOME_VALUE to 0, that is if i do
#define SOME_VALUE 0
I get output as 0,0,0 itself! if i assign ANY non zero number to
SOME_VALUE then i wil get the first answer which is 0,4,8.
Can any one exaplain me how?

Well, technically, for any non zero value of SOME_VALUE, you
have undefined behavior, so anything might happen:). In fact,
however: any object of type Drive has three subobjects, of types
Base1, Base2 and Base3. These objects must have distinct
addresses within the Drive object (although any one of them can
have the same address as the complete Drive object). In fact,
each of the subobjects will contain something called a vptr; a
pointer that the compiler uses to resolve calls to virtual
functions. It looks like on your machine pointers occupy 4
bytes.

In your expressions, you are converting an integer value to a
Drive*, then converting this to a pointer to one of the bases.
When you convert a Drive* to a pointer to one of the bases, the
compiler will adjust the pointer so that it points to the
correct sub-object. With the additional guarantee that a null
pointer will will stay a null pointer. When your integer value
is 0, you have a null pointer; when it's not, at least with your
implementation, you don't.
 
S

Stuart Redmann

nas wrote:
Consider this example program which i hav taken from some site

#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f() { }
};
class Base2 {
public:
virtual void f() { }
};
class Base3 {
public:
virtual void f() { }
};
class Drive : public Base1, public Base2, public Base3 {
};
// any non zero value because multiply zero with any no is zero
#define SOME_VALUE 1
int main() {
cout << (DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE;
cout << (DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE;
cout << (DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE;
return 0;
}
Output of this prgram is:
048

But the initially how we got 0,4,8 ??? What might be the reson for
this?

Let's take a closer look: If you cast the (integer) value 1 to a Drive* pointer,
the compiler will not change the value but change the type attached to this
value (this means that you now have a Drive* pointer pointing to the memory
location 0x00000001). The memory layout of a Drive object (located at memory
address 1) would like the following scheme:

1 5 9 13 (memory addresses)
_______________________________________________________
| Base1 (4 Bytes) | Base2 (4 Bytes) | Base3 (4 Bytes) |
-------------------------------------------------------
| ' = ptr to VMT ' = ptr to VMT '
| of Base2 of Base3 (4 Bytes)
| + members + members (0 Bytes)
L--: ptr to vtable of Drive (this vtable can be used as VMT for both
Base1 and Drive).

Now if you upcast a pointer to Drive to Base1, the compiler doesn't need to
change the address, as the internal Base1 object inside Drive's memory layout
lays at the internal offset zero. The internal Base2 object has offset 4, so
you'll get the address 5 for the Base2 object.

I hope this makes it a bit clearer for you.

Regards,
Stuart
 
N

nas

nas wrote:

Consider this example program which i hav taken from some site

#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f() { }};

class Base2 {
public:
virtual void f() { }};

class Base3 {
public:
virtual void f() { }};

class Drive : public Base1, public Base2, public Base3 {};

// any non zero value because multiply zero with any no is zero
#define SOME_VALUE 1
int main() {
cout << (DWORD)static_cast<Base1*>((Drive*)SOME_VALUE)-SOME_VALUE;
cout << (DWORD)static_cast<Base2*>((Drive*)SOME_VALUE)-SOME_VALUE;
cout << (DWORD)static_cast<Base3*>((Drive*)SOME_VALUE)-SOME_VALUE;
return 0;}

Output of this prgram is:
048




Let's take a closer look: If you cast the (integer) value 1 to a Drive* pointer,
the compiler will not change the value but change the type attached to this
value (this means that you now have a Drive* pointer pointing to the memory
location 0x00000001). The memory layout of a Drive object (located at memory
address 1) would like the following scheme:

1 5 9 13 (memory addresses)
_______________________________________________________
| Base1 (4 Bytes) | Base2 (4 Bytes) | Base3 (4 Bytes) |
-------------------------------------------------------
| ' = ptr to VMT ' = ptr to VMT '
| of Base2 of Base3 (4 Bytes)
| + members + members (0 Bytes)
L--: ptr to vtable of Drive (this vtable can be used as VMT for both
Base1 and Drive).

Now if you upcast a pointer to Drive to Base1, the compiler doesn't need to
change the address, as the internal Base1 object inside Drive's memory layout
lays at the internal offset zero. The internal Base2 object has offset 4, so
you'll get the address 5 for the Base2 object.

I hope this makes it a bit clearer for you.

Regards,
Stuart

Thank you so much..your answer smashed my questions!
Thanks again
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top