Problem: references mess up inheritance. Doesn't make sense.

L

Lou Pecora

Problem: If I inherit an object B from A and use references in B to
data in A, arrays of B objects which are pointed to by an A pointer
causes "EXC_BAD_ACCESS" errors at the point shown in the code below.
Removing the references cures the problem. Throughout, the correct
virtural functions are called.

The code is dirt simple (below). Can anyone explain why reference in
the interited object ruin the array structure in some way that causes a
crash? If I remove the references in B (w and z) and their
initialization in the B creator, the code runs fine and the correct
(virtual) B::prn_data() is called.

I'm running gcc 3.3 on a Mac OS X 10.3.9 Powerbook using Xcode. But
this seems like a generic C++ question.

Thanks for any help.

--- The code - header -----------------------------------

// junk.h

class A {
public:
float x,y;

A();
virtual void prn_data();
};

class B: public A {
public:
float &w,&z;

B();
virtual void prn_data();
};

--- The code - source .cpp -----------------------------------

// ---- Junk Test --------------------------
void junktest() {

A *pb=new B[2]; // NOTE: the pointer is of type A.

pb[0].prn_data();
pb[1].prn_data(); // <--- ERROR here
}

// --- A Creator -----------------
A::A() {
x=1.0; y=2.0;
}
// Print data -- virtual
void A::prn_data() {
printf("In A\n");
}

// --- B Creator -----------------
B::B():A(), w(x), z(y)
{
}
// Print data
void B::prn_data() {
printf("In B\n");
A::prn_data();
}

-- Lou Pecora (my views are my own) REMOVE THIS to email me.
 
V

Victor Bazarov

Lou said:
Problem: If I inherit an object B from A and use references in B to
data in A, arrays of B objects which are pointed to by an A pointer
causes "EXC_BAD_ACCESS" errors at the point shown in the code below.
Removing the references cures the problem. Throughout, the correct
virtural functions are called.

The code is dirt simple (below).

Please next time do not indicate different files. Post your code as one
contiguous text -- that's what it should be. Everybody reading c.l.c++
should be able to simply copy your code from the message and paste it in
a text editor, save it as a file, compile it [, run it] and see the same
thing you see.
> Can anyone explain why reference in
the interited object ruin the array structure in some way that causes a
crash?

No, I cannot explain why behaviour changes without going into compiler-
specific stuff (which is OT). The behaviour is _undefined_ either way.
It just looks like the desired behaviour when you have the derived class
object add no data. Change the references to be regular 'float' values
and you will have the same crash, most likely. Again, the behaviour is
undefined.

The reason the behaviour is undefined is simple: you treat an array of
derived class objects as if it were an array of the base class objects.
You can't do that and expect your program to work.
> If I remove the references in B (w and z) and their
initialization in the B creator, the code runs fine and the correct
(virtual) B::prn_data() is called.

I'm running gcc 3.3 on a Mac OS X 10.3.9 Powerbook using Xcode. But
this seems like a generic C++ question.

Thanks for any help.

--- The code - header -----------------------------------

// junk.h

class A {
public:
float x,y;

A();
virtual void prn_data();
};

class B: public A {
public:
float &w,&z;

B();
virtual void prn_data();
};

--- The code - source .cpp -----------------------------------

// ---- Junk Test --------------------------
void junktest() {

Shouldn't this function be 'int main()'?
A *pb=new B[2]; // NOTE: the pointer is of type A.

An array of _derived_ class objects is accessed through a pointer to
the base class. This is simply _undefined_behaviour_.
pb[0].prn_data();
pb[1].prn_data(); // <--- ERROR here

Of course it is. The offset to the object is calculated based on the
size of A, not on the _real_ size. pb[1] is presumed to be located
in the wrong place.
}

// --- A Creator -----------------
A::A() {
x=1.0; y=2.0;

Prefer initialisation over assignment. See FAQ.
}
// Print data -- virtual
void A::prn_data() {
printf("In A\n");

'printf' undefined. Did you forget to include some standard header?
}

// --- B Creator -----------------
B::B():A(), w(x), z(y)
{
}
// Print data
void B::prn_data() {
printf("In B\n");
A::prn_data();
}

V
 
L

Lou Pecora

Victor Bazarov said:
Lou said:
Problem: If I inherit an object B from A and use references in B to
data in A, arrays of B objects which are pointed to by an A pointer
causes "EXC_BAD_ACCESS" errors at the point shown in the code below.
Removing the references cures the problem. Throughout, the correct
virtural functions are called.

The code is dirt simple (below).

Please next time do not indicate different files. Post your code as one
contiguous text -- that's what it should be. Everybody reading c.l.c++
should be able to simply copy your code from the message and paste it in
a text editor, save it as a file, compile it [, run it] and see the same
thing you see.

Yes, I left out the main and the includes. Very sorry.
No, I cannot explain why behaviour changes without going into compiler-
specific stuff (which is OT). The behaviour is _undefined_ either way.
It just looks like the desired behaviour when you have the derived class
object add no data. Change the references to be regular 'float' values
and you will have the same crash, most likely. Again, the behaviour is
undefined.

You are right. It had nothing to do with the reference idea. Regular
data crashed it, too.
The reason the behaviour is undefined is simple: you treat an array of
derived class objects as if it were an array of the base class objects.
You can't do that and expect your program to work.


Yes, I see what you mean. I was heading toward that idea. You got
there a lot faster than I. I changed the implementation to one of an
array of pointers to my base class, but then used "new" to have each
array component point to a derived class. Adjusting the code for
pointer rather than object access made it work.

Thank you for your insight.

-- Lou Pecora (my views are my own) REMOVE THIS to email me.
 
D

Dave Townsend

Lou Pecora said:
Problem: If I inherit an object B from A and use references in B to
data in A, arrays of B objects which are pointed to by an A pointer
causes "EXC_BAD_ACCESS" errors at the point shown in the code below.
Removing the references cures the problem. Throughout, the correct
virtural functions are called.

The code is dirt simple (below). Can anyone explain why reference in
the interited object ruin the array structure in some way that causes a
crash? If I remove the references in B (w and z) and their
initialization in the B creator, the code runs fine and the correct
(virtual) B::prn_data() is called.

I'm running gcc 3.3 on a Mac OS X 10.3.9 Powerbook using Xcode. But
this seems like a generic C++ question.

Thanks for any help.

--- The code - header -----------------------------------

// junk.h

class A {
public:
float x,y;

A();
virtual void prn_data();
};

class B: public A {
public:
float &w,&z;

B();
virtual void prn_data();
};

--- The code - source .cpp -----------------------------------

// ---- Junk Test --------------------------
void junktest() {

A *pb=new B[2]; // NOTE: the pointer is of type A.

pb[0].prn_data();
pb[1].prn_data(); // <--- ERROR here
}

// --- A Creator -----------------
A::A() {
x=1.0; y=2.0;
}
// Print data -- virtual
void A::prn_data() {
printf("In A\n");
}

// --- B Creator -----------------
B::B():A(), w(x), z(y)
{
}
// Print data
void B::prn_data() {
printf("In B\n");
A::prn_data();
}

-- Lou Pecora (my views are my own) REMOVE THIS to email me.

Lou,

your problem is here:::

A *pb=new B[2]; // NOTE: the pointer is of type A.

pb[0].prn_data();
pb[1].prn_data(); // <--- ERROR here

You are indexing in consistently - pb is an array of A's, but you actually
put 'B's into it,
when you index at location 1, note that A and B's have different sizes, ,
the address you access is not the address of a valid object and so Kaboom!!
Very Nasty!

Probably you won't see this crash if you didn't invoke the virtual member
functions. When you
try to invoke the virtual functions, the computation to locate the virtual
function pointer will be
hopeless hosed up so you will try to use some invalid address in memory as
the function address..

dave
 
R

ravinderthakur

Dave said:
Lou Pecora said:
Problem: If I inherit an object B from A and use references in B to
data in A, arrays of B objects which are pointed to by an A pointer
causes "EXC_BAD_ACCESS" errors at the point shown in the code below.
Removing the references cures the problem. Throughout, the correct
virtural functions are called.

The code is dirt simple (below). Can anyone explain why reference in
the interited object ruin the array structure in some way that causes a
crash? If I remove the references in B (w and z) and their
initialization in the B creator, the code runs fine and the correct
(virtual) B::prn_data() is called.

I'm running gcc 3.3 on a Mac OS X 10.3.9 Powerbook using Xcode. But
this seems like a generic C++ question.

Thanks for any help.

--- The code - header -----------------------------------

// junk.h

class A {
public:
float x,y;

A();
virtual void prn_data();
};

class B: public A {
public:
float &w,&z;

B();
virtual void prn_data();
};

--- The code - source .cpp -----------------------------------

// ---- Junk Test --------------------------
void junktest() {

A *pb=new B[2]; // NOTE: the pointer is of type A.

pb[0].prn_data();
pb[1].prn_data(); // <--- ERROR here
}

// --- A Creator -----------------
A::A() {
x=1.0; y=2.0;
}
// Print data -- virtual
void A::prn_data() {
printf("In A\n");
}

// --- B Creator -----------------
B::B():A(), w(x), z(y)
{
}
// Print data
void B::prn_data() {
printf("In B\n");
A::prn_data();
}

-- Lou Pecora (my views are my own) REMOVE THIS to email me.

Lou,

your problem is here:::

A *pb=new B[2]; // NOTE: the pointer is of type A.

pb[0].prn_data();
pb[1].prn_data(); // <--- ERROR here

You are indexing in consistently - pb is an array of A's, but you actually
put 'B's into it,
when you index at location 1, note that A and B's have different sizes, ,
the address you access is not the address of a valid object and so Kaboom!!
Very Nasty!

Probably you won't see this crash if you didn't invoke the virtual member
functions. When you
try to invoke the virtual functions, the computation to locate the virtual
function pointer will be
hopeless hosed up so you will try to use some invalid address in memory as
the function address..

dave

just one query:

will this work if i use

(a + 0)->prnt_data() and (a + 1)->prnt_data();
and if not why ???


thanks
rt.
 
E

Earl Purple

This should work:

#include <iostream>

class A
{
protected:
float x;
float y;
public:
A() : x( 1.0 ), y( 2.0 ) {}
virtual ~A() {}
virtual void prn_data() const { std::cout << "in A prn_data\n"; }
};

class B : public A
{
protected:
float & w;
float & z;
public:
B() : w(x), z(y) {}
virtual void prn_data() const
{
std::cout << "in B::prn_data\n";
A::prn_data();
}
};

int main()
{
B b[2];
A* pb[2];
pb[0] = &b[0];
pb[1] = &b[1];

pb[0].prn_data();
pb[1].prn_data();
}
 
L

Lou Pecora

Lou,

your problem is here:::

A *pb=new B[2]; // NOTE: the pointer is of type A.

pb[0].prn_data();
pb[1].prn_data(); // <--- ERROR here

You are indexing in consistently - pb is an array of A's, but you actually
put 'B's into it,
when you index at location 1, note that A and B's have different sizes, ,
the address you access is not the address of a valid object and so Kaboom!!
Very Nasty!

Probably you won't see this crash if you didn't invoke the virtual member
functions. When you
try to invoke the virtual functions, the computation to locate the virtual
function pointer will be
hopeless hosed up so you will try to use some invalid address in memory as
the function address..

dave

Thank you, Dave. That's it. I switched to arrays of pointers to the
base object which are then pointed to the derived object. That cured
the problem.

-- Lou Pecora (my views are my own) REMOVE THIS to email me.
 
L

Lou Pecora

"Earl Purple said:
This should work:

#include <iostream>

class A
{
protected:
float x;
float y;
public:
A() : x( 1.0 ), y( 2.0 ) {}
virtual ~A() {}
virtual void prn_data() const { std::cout << "in A prn_data\n"; }
};

class B : public A
{
protected:
float & w;
float & z;
public:
B() : w(x), z(y) {}
virtual void prn_data() const
{
std::cout << "in B::prn_data\n";
A::prn_data();
}
};

int main()
{
B b[2];
A* pb[2];
pb[0] = &b[0];
pb[1] = &b[1];

pb[0].prn_data();
pb[1].prn_data();
}

Thanks, Earl. That's basically what I ended up with. Except I have

pb[0]->prn_data(); etc. in main().

That seems to work for me. pb[0], pb[1] are pointers to B, right?

-- Lou Pecora (my views are my own) REMOVE THIS to email me.
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top