0

I have a weird problem. I made an example explaining what is the problem. I have 4 classes, one that gets a pointer to a class which is inherent to 2 others. Here is what it looks like : The inherences classes:

class classA{
public:
  classA(){}
  virtual std::string getType(){return "classA";}
  classA& operator=(const classA& classa) {return *this;}

};

class classB: public classA {
  int b;
public:
  classB(int n){b=n;}
  virtual std::string getType() { return "classB"; }
  void setB(const int b){this->b=b;}
  int getB() const{return this->b;}
};

class classC: public classA {
  int c;
public:
  classC(int n){c=n;}
  virtual std::string getType() { return "classC"; }
  void setC(const int c){this->c=c;}
  int getC() const{return this->c;}
};

The only important thing is the getType() function.

Here is now the class that get a pointer to classA

class superClass{
  classA* _classA;
  int nb;
public:
  superClass(){nb=0;}
  void addElement(classA& e){
    classA *newTab=new classA[++nb]; // create tab as the same size than the other +1
    for(int i=0;i<nb-1;i++)
      newTab[i]=_classA[i]; // add element from the old class to the new one
    newTab[nb-1]=e; // add the element
    //delete[] _classA; 
    _classA=newTab; // now copy it to the class
    //delete[] newTab;
  }
  classA* getClass() {return _classA;}
  int getNb() const{return this->nb;}

  void displayElements(){
    for(int i=0;i<getNb();i++)
        std::cout << _classA[i].getType() << std::endl;

  }
};

addElemment() is a function that malloc a classA element with one space more, it is filled with the ancien elements then it adds the new element and here it goes. Is works BUT the problem is here. I don't use classA element, only its children. I want to add classB elements and classC elements the the superClass and get the class type with getType(); Here is the main file

int main(int argc, char const *argv[])
{
  classB *classb = new classB(9);
  classC *classc = new classC(10);

  superClass super;
  super.addElement(*classb);
  super.displayElements();
  // Display "classA" instead of "classB"

  super.addElement(*classc);
  super.displayElements();
  // Display "classA" and "classA" instead "classB" and "classC"

  //std::cout << classb->getType() << std::endl; // return ClassA
  //std::cout << classc->getType() << std::endl; // return ClassA

  return 0;
}

I just want my program displaying the right class, the child one class. The problem comes with addElement() I think. I tried to use virtual std::string getType()=0; but it still doesn't work, it changes nothing.

I also tried using template but changes nothing and does not work

My question : I want my program displaying the child class instead of classA everytime.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Hearner
  • 2,711
  • 3
  • 17
  • 34
  • 2
    Hint: __object slicing__ – Emil Laine Apr 21 '16 at 10:13
  • I did not know about it, I'm looking at it thank you – Hearner Apr 21 '16 at 10:16
  • I understand what is it but in my example I cannot pass the address of the superClass because the function is already is a superClass::superClass() with no parameters – Hearner Apr 21 '16 at 10:19
  • Your program is a memory leak. Anyway, why do you think you need manual memory allocation rather than a smart pointer? Or, really, why use pointers at all here? In this case, you could just as easily declare instances on the stack and take references to them to implement polymorphism. Automatic memory management, nicer syntax, everyone's a winner. – underscore_d Apr 21 '16 at 10:44
  • As I said, this is just an example, there are problems that there aren't in my program. Are you telling me that "new" is a bad thing to do ? I learnt C and I was told that new is the same as using new – Hearner Apr 21 '16 at 11:20

2 Answers2

1

You should change declaration member _classA in superClass to the following: classA** _classA;. So it would be like this:

class superClass
{
   classA** _classA;
   int nb;
public:
   superClass():_classA(0) // you also should initialize this to avoid crash while first delete[] of this _classA
   {
      nb = 0;
   }

   ~superClass() // also you should add destructor to free memory
   {
      for (int i = 0; i < nb; i++)
      {
          delete _classA[i];
          _classA[i] = nullptr;
      }
      delete[] _classA;
      _classA[i] = nullptr;
   }

   void addElement(classA& e)
   {
      int oldSize = nb;
      nb++; // increment the size separately for clarity
      classA **newTab = new classA*[nb]; // create tab as the same size than the other +1
      for (int i = 0; i < oldSize; i++)
         newTab[i] = _classA[i]; // add element from the old class to the new one
      classA* newElement = new classA(e); // use the copy-constructor
      newTab[oldSize] = newElement; // add the element
      delete[] _classA; // now you can free it
      _classA = newTab; // now copy it to the class
   }
   classA** getClass()
   {
      return _classA;
   }
   int getNb() const
   {
      return this->nb;
   }

   void displayElements()
   {
      for (int i = 0; i < getNb(); i++)
         std::cout << _classA[i]->getType() << std::endl;

   }
};
Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Thank you, using ** makes the trick. Can you explain me why this works ? Thank you very much but I'd like to know why ^^ – Hearner Apr 21 '16 at 11:20
  • ’~superClass() { delete[] _classA; }’ crashes at the end of the program (signal SIGABRT) – Hearner Apr 21 '16 at 11:33
  • No way if you have properly initialized the _classA member i.e. please look at constructor once more that it should be "superClass():_classA(0)" to avoid such crash. – Leszek Kosinkiewicz Apr 21 '16 at 11:47
  • Why shouldn't initialize _classA as a new classA*[nb] ?Isn't it a good way to allocate the memory ? – Hearner Apr 21 '16 at 11:57
  • When superClass object is created the nb is equal 0, so does a new classA*[0] make sense ? - I think not. Wile creation such object has not any element added by "addElement" (it is obvious) and also "delete" and "delete[]" check if released pointer is null and work fine. new classA*[0] makes dandling pointer. – Leszek Kosinkiewicz Apr 21 '16 at 12:10
  • Ok I see, it's just that I was told to initialize pointer to NULL instead of 0 – Hearner Apr 21 '16 at 12:39
  • 1
    "using ** makes the trick" this is a pointer to pointer i.e. this is a table of pointers which a initialized by pointer in addElement(e) method. all pointers are classA* type but individual pointer points to any of derived object from classA. By the way destructor of classA should be virtual. – Leszek Kosinkiewicz Apr 21 '16 at 12:40
  • The destructor here has a potential memory leak. You delete the pointer to the array of pointers, but you leave the pointers in the array alone. If those were pointing to dynamic memory, all of that memory is now leaked. Conversely, the `addElement` function is not taking ownership of the elements it is storing (a bad practice), so it is possible that objects being stored go out of scope (local variables) in which case you have dangling pointers in the array. This entire answer should really be refactored to clean up these problems before being the accepted answer. – Zac Howland Apr 22 '16 at 00:05
  • Yes, of course, but we should not resolve all problems in this topic. questions was about how to resolve the following : "My question : I want my program displaying the child class instead of classA everytime." and I think that we should not repair all things - I keep in mind that it is only simple program as it is. – Leszek Kosinkiewicz Apr 22 '16 at 07:03
  • I have a problem. In fact my program is more complicated than the example. Making the class ** make it works but in fact it's like classA has a pointer to another class (lets call it classChild). superClass has ** classA, and classA has **classChild. The problem is that i can't add child fields into class A. Have I to add more '*' anywhere ? (superClass posseses pointer to classA, and classA possesses pointer to classChild). The getterclassChild is always NULL – Hearner Apr 22 '16 at 12:09
  • I have something like : (*superClass).getClassA()->getClassChild()->getName() but doesn't work EXC_BAD_ACCESS – Hearner Apr 22 '16 at 13:16
  • I'll ask another question – Hearner Apr 22 '16 at 17:53
  • I think that you miss []operator in above example, but this is not a problem. Why don't you use STL, or boost containers to achieve good solution. also you should use smart pointers to avoid memory leaks. – Leszek Kosinkiewicz Apr 22 '16 at 19:59
  • @LeszekKosinkiewicz Answering just his question is one thing. This answer, prior to the edits, provided an answer that was inaccurate as it introduced new problems that were not in the original question. – Zac Howland Apr 23 '16 at 04:06
0

newTab is an array of classA. Therefore, it cannot contain classB objects, only classA objects.

newTab[nb-1]=e;

Here, if e refers to a classB object, this assignment slices the classB part away from it, so it becomes a classA object and can fit in the array. This is known as object slicing.

Community
  • 1
  • 1
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • Thank you for taking the time to answer. I read thing about it but How to avoid it ? What should I do to display the right thing in my example ? – Hearner Apr 21 '16 at 10:27