开发者

array of derived classes doesnt work if derived class has private variables

I have an abstract base class and 2 different classes that implements a virtual function from the baseclass.

I put these in an array, and for "derived1" class this works. If I however make an array of "derived2" class that has some extra private variables, the code will compile but errors at runtime.

#include <iostream>
class base{
protected:
  int inner_a;
  int inner_b;
public:
  void setInner(int a,int b){inner_a=a;inner_b=b;};
  virtual int doStuff()=0;
};


class derived1: public base{
public:
  virtual int doStuff();
};



class derived2: public base{
private:
  int tmpVar;//works if I remove
public:
  int doStuff();
};


int derived2::doStuff(){

  return 开发者_如何学Pythoninner_a-inner_b;
}

int derived1::doStuff(){
    return inner_a+inner_b;
}



int main(){
  base *classAry1 = new derived1[3];//this works
  base *classAry2 = new derived2[2];//derived2 has extra private variables


  classAry1[0].setInner(1,3);
  classAry1[1].setInner(10,7);
  std::cout <<classAry1[0].doStuff() <<std::endl;;
  std::cout <<classAry1[1].doStuff() <<std::endl;


  classAry2[0].setInner(1,3);
  classAry2[1].setInner(10,7);
  std::cout <<classAry2[0].doStuff() <<std::endl;;
  std::cout <<classAry2[1].doStuff() <<std::endl;


  return 0;
}

Can anyone help me, on how to put deriveded classes in a std array?

Thanks

edit:

The code segfaults, and valgrind tells me

-2

==25096== Use of uninitialised value of size 8
==25096==    at 0x400AC9: main (abc.cpp:52)
==25096== 
==25096== Invalid read of size 8
==25096==    at 0x400AC9: main (abc.cpp:52)
==25096==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==25096== 
==25096== 
==25096== Process terminating with default action of signal 11 (SIGSEGV)
==25096==  Access not within mapped region at address 0x0
==25096==    at 0x400AC9: main (abc.cpp:52)


An array of derived1 objects (or derived2 objects) cannot be interpreted as an array of base objects. Arrays are not polymorphic. Only standalone object can be polymorphic, i.e. derived1 has IS-A relationship with base. But array of derived1 does not have IS-A relationship with array of base. Neither of your arrays (neither classAry1 nor classAry2) can really "work".

In other words, this

base *classAry1 = new derived1[3];
base *classAry2 = new derived2[2];

already does not make any sense, even though it is formally well-formed code.

The first array "appears to work" just by pure accident. The behavior of your code is undefined, even when you work with classAry1.

If you want to have an array (or a container) that stores polymorphic entities, you have to store pointers to actual objects in that array, instead of storing the actual objects themselves.

In your specific case, the code can be rewritten in the following way. (It doesn't look very nice and I'm just doing it to illustrate the principle, since without knowing your full intent it is hard to choose the best approach)

int main(){
  derived1 *d1s = new derived1[2];
  base **classAry1 = new base *[2];
  classAry1[0] = &d1s[0];
  classAry1[1] = &d1s[1];

  derived2 *d2s = new derived2[2];
  base **classAry2 = new base *[2];
  classAry2[0] = &d2s[0];
  classAry2[1] = &d2s[1];

  classAry1[0]->setInner(1,3);
  classAry1[1]->setInner(10,7);
  std::cout << classAry1[0]->doStuff() << std::endl;;
  std::cout << classAry1[1]->doStuff() << std::endl;

  classAry2[0]->setInner(1,3);
  classAry2[1]->setInner(10,7);
  std::cout << classAry2[0]->doStuff() << std::endl;;
  std::cout << classAry2[1]->doStuff() << std::endl;

  delete[] classAry2;
  delete[] d2s;
  delete[] classAry1;
  delete[] d1s;

  return 0;
}


In general you cannot do what you are trying to do. You are invoking undefined behavior. When a system is faced with undefined behavior it is free to do whatever it wants (including erasing your hard drive) and still be compliant with the standards. The problem is your code.


classAry2[1] => &classAry2 + sizeof (base) which is not equal to the actual derived2 size which is > sizeof (base) or derived1. You need to get to the correct address (2nd element) for classAry2, which is classAry2 + sizeof (derived2).

The easiest workaround would be to access them using an array of pointers to base*. Use base** = allocate array of base* Then assign each element with the correct instance (derived or derived2 or base) That way when you use classAry [n] or classAry++, it will always point to the correct address.


You cannot do that. An array of one type T1 is not convertible to an array of another type T2, even if one is derived from the other.

On your line

  base *classAry1 = new derived1[3];//this works

what you actually have is a base class pointer for the first element of the array, only. The other elements are "lost". Accessing the array members other than the first using the base class pointer is undefined behavior.


read this: http://www.parashift.com/c++-faq/proper-inheritance.html

Extremely well described and and it leaves you with a sense of enlightenment :)


Try using std::vector< base* > instead of a raw array.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜