By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,808 Members | 1,481 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,808 IT Pros & Developers. It's quick & easy.

Why the output for this small pgm so?

P: n/a
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?

Aug 9 '07 #1
Share this Question
Share on Google+
7 Replies


P: n/a
On Aug 9, 11:04 am, nas <nas...@gmail.comwrote:
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

Aug 9 '07 #2

P: n/a
nas
On Aug 9, 12:19 pm, Neelesh Bodas <neelesh.bo...@gmail.comwrote:
On Aug 9, 11:04 am, nas <nas...@gmail.comwrote:


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- Hide quoted text -

- Show quoted text -
I compiled above program in Visual Studio 2005

Aug 9 '07 #3

P: n/a
Neelesh Bodas wrote:
On Aug 9, 11:04 am, nas <nas...@gmail.comwrote:
>>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.
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
Aug 9 '07 #4

P: n/a
nas
On Aug 9, 3:09 pm, Stuart Redmann <DerTop...@web.dewrote:
Neelesh Bodas wrote:
On Aug 9, 11:04 am, nas <nas...@gmail.comwrote:
>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.

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?

Aug 9 '07 #5

P: n/a
On Aug 9, 8:04 am, nas <nas...@gmail.comwrote:
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.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Aug 9 '07 #6

P: n/a
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

Stuart Redmann wrote:
>>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).
nas wrote:
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
Aug 10 '07 #7

P: n/a
nas
On Aug 10, 12:10 pm, Stuart Redmann <DerTop...@web.dewrote:
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

Stuart Redmann wrote:
>Seehttp://www.phpcompiler.org/doc/virtualinheritance.htmlfora 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).
nas wrote:
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
Thank you so much..your answer smashed my questions!
Thanks again

Aug 10 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.