Inheritance tricky question
-
Hi Friends, I came through a interesting question in inheritance. Here is the chunk of code and out put is given below. // Inheritance tricky.cpp : Defines the entry point for the console application. // class Foo { private: int i; public: Foo() { i = 0; } void geti() { cout << i << endl; } }; class Bar : public Foo { private: int j; public: Bar() { j = 1; } void getj() { cout << j << endl; } }; void display(Foo* obj, int ctr) { for (int i = 0; i < ctr; i++) { ((Foo*)obj + i)->geti(); } } int _tmain(int argc, _TCHAR* argv[]) { Foo myFoo[3]; display(myFoo, 3); Bar myBar[3]; display(myBar, 3); return 0; } and Output is 0 0 0 0 1 0 The first 3 line is 0 that's fine. But how the 2nd last is 1 ??? Is there is any way that I can get all 0 in output if I am still executing this code Bar myBar[3]; display(myBar, 3); PLease help me out. Thanks in Advance. Regards, Amrit
-
Hi Friends, I came through a interesting question in inheritance. Here is the chunk of code and out put is given below. // Inheritance tricky.cpp : Defines the entry point for the console application. // class Foo { private: int i; public: Foo() { i = 0; } void geti() { cout << i << endl; } }; class Bar : public Foo { private: int j; public: Bar() { j = 1; } void getj() { cout << j << endl; } }; void display(Foo* obj, int ctr) { for (int i = 0; i < ctr; i++) { ((Foo*)obj + i)->geti(); } } int _tmain(int argc, _TCHAR* argv[]) { Foo myFoo[3]; display(myFoo, 3); Bar myBar[3]; display(myBar, 3); return 0; } and Output is 0 0 0 0 1 0 The first 3 line is 0 that's fine. But how the 2nd last is 1 ??? Is there is any way that I can get all 0 in output if I am still executing this code Bar myBar[3]; display(myBar, 3); PLease help me out. Thanks in Advance. Regards, Amrit
myBar[1].i is still 0. The problem here is that you try to apply pointer-arithmetic to a base-class pointer. When you add 1 to
Foo* obj
in the loop in display(..), the pointer is increased by the size ofFoo
, because it's declared as a pointer toFoo
. But it's actually (initially) pointing to instances ofBar
, whose size is larger than that ofFoo
- so after adding 1 to the pointer, it points to some address still within the first instance ofBar
, not to the secondBar
. The output of 1 is whatever happens to be at the address wherei
should be if the pointer was valid. The closest thing you can do to make it work is to use pointers to pointers:void display2(Foo** obj, int ctr)
{
for (int i = 0; i < ctr; i++)
{
(*(obj + i))->geti();
}
}int _tmain(int argc, _TCHAR* argv[])
{
Foo myFoo[3];
display(myFoo, 3);Bar myBar\[3\]; Foo \*myBaz\[3\] = { &myBar\[0\], &myBar\[1\], &myBar\[2\] }; display2(myBaz, 3); return 0;
}
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
-
myBar[1].i is still 0. The problem here is that you try to apply pointer-arithmetic to a base-class pointer. When you add 1 to
Foo* obj
in the loop in display(..), the pointer is increased by the size ofFoo
, because it's declared as a pointer toFoo
. But it's actually (initially) pointing to instances ofBar
, whose size is larger than that ofFoo
- so after adding 1 to the pointer, it points to some address still within the first instance ofBar
, not to the secondBar
. The output of 1 is whatever happens to be at the address wherei
should be if the pointer was valid. The closest thing you can do to make it work is to use pointers to pointers:void display2(Foo** obj, int ctr)
{
for (int i = 0; i < ctr; i++)
{
(*(obj + i))->geti();
}
}int _tmain(int argc, _TCHAR* argv[])
{
Foo myFoo[3];
display(myFoo, 3);Bar myBar\[3\]; Foo \*myBaz\[3\] = { &myBar\[0\], &myBar\[1\], &myBar\[2\] }; display2(myBaz, 3); return 0;
}
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
Hi Sascha, I am not able to understand why we need to take address of Bar objects in line Foo *myBaz[3] = { &myBar[0], &myBar[1], &myBar[2] }; and why we need to pass to pass the address of myBaz to a Foo** ( Double Pointer )? How surprisingly its working fine now? One more thing I still didn't get it hpw it prints 1 for 2nd iteration of Bar object. If I am not wrong, even if we are passing Bar address to Foo pointer, it wil call the geti function of Foo only ? so It should print variable i value that is 0 ? Please clear my doubt. Thanks
-
Hi Sascha, I am not able to understand why we need to take address of Bar objects in line Foo *myBaz[3] = { &myBar[0], &myBar[1], &myBar[2] }; and why we need to pass to pass the address of myBaz to a Foo** ( Double Pointer )? How surprisingly its working fine now? One more thing I still didn't get it hpw it prints 1 for 2nd iteration of Bar object. If I am not wrong, even if we are passing Bar address to Foo pointer, it wil call the geti function of Foo only ? so It should print variable i value that is 0 ? Please clear my doubt. Thanks
Hi Amrit, I'll try to explain it with some diagrams. First, the simple case - you probably know this, but I'll show it for completeness. The class
Foo
has a single member of typeint
(int32), so it has a size of 4 bytes.# 3 instances of Foo in memory with a Foo* pointer pointing to it:
Foo myFoo[3]; // in _tmain(..)
Foo* ptr = myFoo; // calling display(..) (I renamed *obj to *ptr here)
ptr ptr+1 ptr+2 // the loop in display(..)
(100) (100+4) (100+8)
| | |
v v v
Memory address: 100..103 104..107 108..111 // (artificially chosen address)
Instance: --Foo1-- --Foo2-- --Foo3--
Members: ---i---- ---i---- ---i----
Now with the class
Bar
(8 bytes) and your original approach:# 3 instances of Bar in memory with a Foo* pointer pointing to it:
Bar myBar[3]; // in _tmain(..)
Foo* ptr = myBar; // calling display(..)
ptr ptr+1 ptr+2 // the loop in display(..)
(100) (100+4) (100+8) // here's why it doesn't work:
| | | // ptr is Foo* so ptr+1 still means adding the size of Foo (4) !
v v v
Memory address: 100........107 108........115 116........123
Instance: -----Bar1----- -----Bar2----- -----Bar3-----
Members: ---i---___j___ ---i---___j___ ---i---___j___
Value: 0 1 0 // and there's your strange output! ;-)
And now with pointers to pointers. Let's say we're on a 32bit-system here, then a pointer has the size of 4 bytes (32 bit). So, when doing pointer arithmetic with pointers to pointers, adding 1 means always increasing its pointed-to-address by 4 bytes. It doesn't have anything to do with the size of the class that's being pointed to by the pointer that's being pointed to :-D
# 3 instances of Bar in memory with a Foo** pointer pointing to Bar* pointers:
Bar myBar[3]; // in _tmain(..)
Foo *myBaz[3] = { &myBar[0], &myBar[1], &myBar[2] };Value: 100 108 116
Foo** pptr = myBaz; // calling display2(..) (for clarity, I named it pptr here)
pptr pptr+1 pptr+2
(200) (200+4) (200+8) // see explanati