pointer arithmetic with inheritance

C

ceo

Hi,

Following is a program that doesn't give the expected output, not sure
what's wrong here. I'm adding the size of derived class to the base
class pointer to access the next element in the array. Why does bp
point to some address that is not &d[1]?

Please clarify.

Thanks,
Ceo

#include <iostream>
using namespace std;

class base {
int i;
public:
void set_i(int num) { i=num; }
int get_i() { return i; }
};

class derived: public base {
int j;
public:
void set_j(int num) {j=num;}
int get_j() {return j;}
};

int main()
{
base *bp;
derived d[2];

bp = d;

d[0].set_i(1);
d[1].set_i(2);

cout << "\n sizeof (base): " << sizeof(base) << endl;
cout << "\n sizeof (derived): " << sizeof(derived) << endl << endl;

cout << " d[0] addr: " << &d[0] << endl;
cout << " d[1] addr: " << &d[1] << endl;
cout << " bp addr: " << bp << endl << endl;

cout << " i = " << bp->get_i() << endl << endl;
bp = bp + sizeof(derived);
cout << " bp addr: " << bp << endl << endl;
cout << " i = " << bp->get_i() << endl << endl;

return 0;
}

output on my machine:
--------------------
sizeof (base): 4

sizeof (derived): 8

d[0] addr: 0012FF6C
d[1] addr: 0012FF74
bp addr: 0012FF6C

i = 1

bp addr: 0012FF8C

i = 3149472
 
A

Aslan Kral

haber iletisinde sunlari said:
Hi,

Following is a program that doesn't give the expected output, not sure
what's wrong here. I'm adding the size of derived class to the base
class pointer to access the next element in the array. Why does bp
point to some address that is not &d[1]?

Please clarify.

Thanks,
Ceo

#include <iostream>
using namespace std;

class base {
int i;
public:
void set_i(int num) { i=num; }
int get_i() { return i; }
};

class derived: public base {
int j;
public:
void set_j(int num) {j=num;}
int get_j() {return j;}
};

int main()
{
base *bp;
derived d[2];

bp = d;

d[0].set_i(1);
d[1].set_i(2);

cout << "\n sizeof (base): " << sizeof(base) << endl;
cout << "\n sizeof (derived): " << sizeof(derived) << endl << endl;

cout << " d[0] addr: " << &d[0] << endl;
cout << " d[1] addr: " << &d[1] << endl;
cout << " bp addr: " << bp << endl << endl;

cout << " i = " << bp->get_i() << endl << endl;
bp = bp + sizeof(derived);

You have a problem here.
bp is pointing to base which is of size 4.
bp = bp + 8 is equal to bp = bp + 4*8 = bp +32;

this should be OK:
bp = (base*)((size_t)bp + sizeof(derived));
cout << " bp addr: " << bp << endl << endl;
cout << " i = " << bp->get_i() << endl << endl;

return 0;
}

output on my machine:
--------------------
sizeof (base): 4

sizeof (derived): 8

d[0] addr: 0012FF6C
d[1] addr: 0012FF74
bp addr: 0012FF6C

i = 1

bp addr: 0012FF8C

i = 3149472
 
A

Axter

ceo said:
Hi,

Following is a program that doesn't give the expected output, not sure
what's wrong here. I'm adding the size of derived class to the base
class pointer to access the next element in the array. Why does bp
point to some address that is not &d[1]?

Please clarify.

Thanks,
Ceo

#include <iostream>
using namespace std;

class base {
int i;
public:
void set_i(int num) { i=num; }
int get_i() { return i; }
};

class derived: public base {
int j;
public:
void set_j(int num) {j=num;}
int get_j() {return j;}
};

int main()
{
base *bp;
derived d[2];

bp = d;

d[0].set_i(1);
d[1].set_i(2);

cout << "\n sizeof (base): " << sizeof(base) << endl;
cout << "\n sizeof (derived): " << sizeof(derived) << endl << endl;

cout << " d[0] addr: " << &d[0] << endl;
cout << " d[1] addr: " << &d[1] << endl;
cout << " bp addr: " << bp << endl << endl;

cout << " i = " << bp->get_i() << endl << endl;
bp = bp + sizeof(derived);
cout << " bp addr: " << bp << endl << endl;
cout << " i = " << bp->get_i() << endl << endl;

return 0;
}

output on my machine:
--------------------
sizeof (base): 4

sizeof (derived): 8

d[0] addr: 0012FF6C
d[1] addr: 0012FF74
bp addr: 0012FF6C

i = 1

bp addr: 0012FF8C

i = 3149472

You can not use pointer arithmetic using a base class pointer that
points to a derive class.

You can however use a pointer to a pointer to get pointer arithmetic to
work with a base class type.
Example:

class Base
{
public:
Base():m_x(999){}
virtual void OutPutData()=0;
int m_x;
};

class SubClass : public Base
{
public:
SubClass():m_y(1234){}
void OutPutData(){
cout << m_y << endl;
}
long m_y;
};



int main(int argc, char* argv[])
{
Base *b[2];
SubClass s[2];

b[0] = &s[0];
b[1] = &s[1];

Base **ppBase = b;

(*ppBase)->OutPutData();

++ppBase; //Pointer arithmetic

(*ppBase)->OutPutData();


************************************************************************
David Maisonave :-}
Top ten member of C++ Expert Exchange.
http://experts-exchange.com/Programming/Programming_Languages/Cplusplus/
 
K

Karl Heinz Buchegger

ceo said:
Hi,

Following is a program that doesn't give the expected output, not sure
what's wrong here. I'm adding the size of derived class to the base
class pointer to access the next element in the array. Why does bp
point to some address that is not &d[1]?

Because of pointer arithmetic.
Pointer arithmetic automatically multiplies with the size
of the dereferenced pointer type (Thats hard to describe,
but actually is very simple). So what the compiler has
compiled would be the equivalent to:
bp = bp + sizeof(derived);

uncigned char* pBasePtr = bp;
pBasePtr = pBasePtr + ( sizeof( derived ) * sizeof( *pBasePtr ) );
bp = (base*)pBasePtr;

You may now figure out on your own, why this will not get the
result you expect.
 
C

ceo

bp = (base*)((size_t) bp + sizeof(derived));

Thanks, this works. I got the idea. The following worked too.

bp = bp + sizeof(derived)/sizeof(base);
 
P

Pete Becker

However, it's not guaranteed that size_t is large enough to store a
pointer value. Use (char*).
Thanks, this works. I got the idea. The following worked too.

bp = bp + sizeof(derived)/sizeof(base);

Only by accident. If sizeof(base) is not a divisor of sizeof(derived)
the value will be too small.

Bottom line: don't play this sort of game. There are too many ways to go
astray.
 
A

Aslan Kral

haber iletisinde sunlari said:
Thanks, this works. I got the idea. The following worked too.

bp = bp + sizeof(derived)/sizeof(base);
Just by chance. Add a variable in base or derived, you will see why.
 
O

Old Wolf

Pete said:
However, it's not guaranteed that size_t is large enough to store a
pointer value. Use (char*).

Bottom line: don't play this sort of game. There are too many ways to go
astray.

I think the behaviour is still undefined, and a bounds-checking
implementation could decide that you have exceeded the bounds of
*bp .

Perhaps this would be better:
bp = dynamic_cast<derived *>(bp) + 1;

I guess a good compiler would optimise this dynamic cast
to happen at compile-time for this particular example,
so there would be no performance penalty.
 
P

Pete Becker

Old said:
I think the behaviour is still undefined, and a bounds-checking
implementation could decide that you have exceeded the bounds of
*bp .

I don't see it.
Perhaps this would be better:
bp = dynamic_cast<derived *>(bp) + 1;

No, base has no virtual functions.
 

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

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top