-2

I've got a problem with type casting from base class to derived (I'm casting because I'm sure that object is that exact type). here's my code (simplified):

class MyCollection 
{
public:
 Element* Get(int i) {
  return elements[i]; 
 }
 void Add(Element* element) {
   //finding i
   elements[i] = element;
 }
private:
 Element* elements[100]; 
}

class Element {
 public:
  int ID; 
}

class SpecialElement : public Element 
{
public:
 SpecialElement(char* name) { 
   this-> Name = name; 
 }
 char* GetName() { return Name; }
private:
 char* Name; 
}

Now when I'm add to MyCollection object of SpecialElement when I put breakpoint at the moment of adding and cast my argument of Add method in Immediate Window and call GetName method it return me Name of object, but when I do something like this:

void main() {
 MyCollection coll = new MyCollection();
 coll.Add(new SpecialElement("MyName"));
 SpecialElement* foundElement = (SpecialElement*)coll->Get(0); 
 foundElement->GetName(); //Error
}

I'm wondering why is that? Isn't founded object of type SpecialElement?

TrN
  • 1,230
  • 2
  • 17
  • 32
  • 5
    Don't use `void main()`: http://www2.research.att.com/~bs/bs_faq2.html#void-main – chris May 24 '12 at 21:19
  • 1
    Way overuse of dynamic allocation. And bad use of strings. And abuse of points. – Puppy May 24 '12 at 21:21
  • 3
    The collection smells like **slicing** all over... – K-ballo May 24 '12 at 21:21
  • 3
    Clean up the example code so it compiles (e.g. not mixing pointers and objects, etc.). Right now it's impossible to tell what is a "real" error amidst all the "fake" typo-type errors. – tmpearce May 24 '12 at 21:24
  • Your code doesn't compile. Reducing your code to the simplest thing that produces the problem is really good idea -- you often end up finding the error on your own that way -- but you should make sure it actually compiles before posting it. This code contains tons of errors, which complicates the task of anyone reviewing it. – Mud May 24 '12 at 21:24
  • For one `this->Name = name;` in the constructor is very bad code. You should be doing a deep copy of the string, and given more information about what the error is I suspect this is the root cause of your problem at runtime – Dan F May 24 '12 at 21:25
  • @SachinKainth and future readers: [What is the slicing problem in C++?](http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c). – Jesse Good May 24 '12 at 21:28

3 Answers3

6
 Element* Get(int i) {
  return elements[i]; 
 }
 void Add(Element* element) {
   //finding i
   elements[i] = element;
 }

How does this even compile? You're assigning an Element* to an Element, and vice versa, but they are entirely different things. Your whole logic is nonsensical.

You're over-using dynamic allocation, assuming reference semantics, and bad char* strings. Get a C++ book.

Also, this class already exists- it's std::array<Element*, 100>. Or std::vector<Element*>, if you want dynamic size.

Puppy
  • 144,682
  • 38
  • 256
  • 465
6

You're casting it to base Element and thereby slicing your SpecialElement object. The cast back to the original type, from your base Element has lost the data Name as that is not part of the base.

AFAIK, you cannot do what you're trying to do.

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
  • He can do it, but this storage array needs to contain *pointers* (i.g. `Element* elements[100]` rather than `Element elements[100]`) to avoid slicing. – Mud May 24 '12 at 21:26
1

You should use Element* elements[100]; and update your code appropriately, otherwise using object assignment instead of pointer assignment kills polymorphism.

Hakan Serce
  • 11,198
  • 3
  • 29
  • 48