如果派生类具有私有变量,则派生类的数组不起作用

时间:2011-06-07 23:18:55

标签: c++ arrays pointers polymorphism

我有一个抽象基类和2个不同的类,它们从基类实现虚函数。

我把它们放在一个数组中,对于“derived1”类,这个有效。 但是,如果我创建一个“derived2”类的数组,它有一些额外的私有变量,代码将在运行时编译但是错误。

#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 inner_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;
}

任何人都可以帮助我,如何将衍生类放在std数组中?

由于

编辑:

代码段错误,valgrind告诉我

-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)

6 个答案:

答案 0 :(得分:7)

derived1个对象(或derived2个对象)的数组不能解释为base个对象的数组。数组不是多态的。只有独立对象可以是多态的,即derived1base具有IS-A关系。但array of derived1array of base没有IS-A关系。您的阵列(classAry1classAry2)都不能真正“正常工作”。

换句话说,这个

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

已经没有任何意义,即使它是形式正确的代码。

第一个阵列“似乎工作”只是纯粹的意外。即使您使用classAry1

,代码的行为也是未定义的

如果你想拥有一个存储多态实体的数组(或容器),你必须将指针存储到该数组中的实际对象,而不是存储实际的对象本身。

在您的特定情况下,可以通过以下方式重写代码。 (它看起来不太好,我只是这样做来说明原理,因为不知道你的完整意图很难选择最好的方法)

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;
}

答案 1 :(得分:1)

一般来说,你无法做你想做的事。您正在调用未定义的行为。当系统面临未定义的行为时,它可以随心所欲地做任何事情(包括擦除硬盘)并且仍然符合标准。问题是你的代码。

答案 2 :(得分:1)

classAry2 [1] =&gt; &amp; classAry2 + sizeof(base),它不等于实际的derived2大小 这是> sizeof(base)或derived1。 您需要到达classAry2的正确地址(第2个元素),即 classAry2 + sizeof(derived2)。

最简单的解决方法是使用指向base *的指针数组来访问它们。 使用base ** =分配基数组* 然后为每个元素分配正确的实例(派生或派生2或基础) 这样当你使用classAry [n]或classAry ++时,它总是指向正确的地址。

答案 3 :(得分:0)

你做不到。一个类型T1的数组不能转换为另一个类型T2的数组,即使一个是从另一个派生的。

在你的行上

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

你实际拥有的是数组的第一个元素的基类指针,。其他元素“丢失”。使用基类指针访问第一个以外的数组成员是未定义的行为。

答案 4 :(得分:0)

请阅读:http://www.parashift.com/c++-faq/proper-inheritance.html

非常好的描述,并且让你有一种启蒙感:)

答案 5 :(得分:-1)

尝试使用std :: vector&lt;基数*&gt;而不是原始数组。

相关问题