0

I'm pretty new to object oriented programming in C++, and I can't find a solution to the following problem, I hope this is even possible.

I've got 3 classes: Base and Child, Child2.

All of them got the function talk();.

I want to store Base, Child and Child2 objects in an array, and iterate through them and execute their talk() functions.

This is what I want them to print:

- Base: "base"
- Child: "child"
- Child2: "child2"

Here are my classes:

class Base {
public:
    virtual void talk() {
        printf("base\n");
    }
}

class Child : public Base {
public:
    using Base:draw;
    void talk() {
        printf("child\n");
    }
}

class Child2 : public Base {
public:
    using Base:draw;
    void talk() {
        printf("child2\n");
    }
}

here is my array:

Base objects[3];
objects[0] = Base();
objects[1] = Child();
objects[2] = Child2();

for(int i = 0; i < 3; i++) {
    objects[i]->talk();
}

And the output should be:

base
child
child2
Morten
  • 2,148
  • 2
  • 15
  • 16
Bert Bijn
  • 337
  • 1
  • 9

3 Answers3

3

Your code is slicing the objects. When you assign a variable of the base class to the value of derived class, you end up with a base object. At this point, nothing is left of the original derived class, all you have is a base class.

In C++ the way to treat objects polymorphically - that is, to retain the information of original type - is to use either a reference or a pointer. However, you can not put references into arrays.

Which means, you need an array of pointers - but not raw pointers. You want so-called smart pointers. Putting it all together, this is how your code should look like:

std::unique_ptr<Base> objects[3] = {new Base(), new Child(), new Child2()};

for(int i = 0; i < 3; i++) {
    objects[i]->talk();
}
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • @KarolyHorvath, unsure what that means. – SergeyA Jan 26 '16 at 15:49
  • Read the question. Again. Carefully. – Karoly Horvath Jan 26 '16 at 15:49
  • @KarolyHorvath, I did, and I also see OP wants to display class names in the given example, most likely, to illustrate the problem OP is having in the real code. But I am not sure what is the significance of this. – SergeyA Jan 26 '16 at 15:51
  • That's his *actual question*. Since he says the code displays the texts, we can assume he was using some kind of pointers, otherwise the code wouldn't even compile! – Karoly Horvath Jan 26 '16 at 15:52
  • @KarolyHorvath, the code as it is can never compile. Also, OP haven't appeared in the comments since asking the question, so it's really hard to second-guess his intentions... I do not know. I use the question as in illustration of slicing and using polymorphic objects in arrays - this might be helpful to someone else. How else I can use it, I do not know. – SergeyA Jan 26 '16 at 15:55
  • Sorry for the late answer @SergeyA – Bert Bijn Nov 16 '18 at 16:25
  • This is the solution that helped me. I tried this, and played with it until late at night. Ended up months later with some sort of a graphical user interface library for the nintendo 3DS, this helped me a lot! Almost 3 years later (job in backend development PHP) and I completely forgot everything about C++. Came across this post and it makes me want to program c++ again! thanks – Bert Bijn Nov 16 '18 at 16:29
-1

Perhaps something like this?

#include <iostream>
#include <cstdio>

class Base 
{
  public:
    virtual void talk() 
    {
      printf("base\n");
    }
};

class Child : public Base 
{
  public:
    void talk() 
    {
      printf("child\n");
    }
};

class Child2 : public Base 
{
  public:
    void talk()
    {
      printf("child2\n");
    }
};

int main()
{
  Base** objects;
  objects = new Base * [3];

  objects[0] = new Base();
  objects[1] = new Child();
  objects[2] = new Child2();

  for(int i = 0; i < 3; i++) 
    objects[i]->talk();
}

Output is:

base
child
child2
Michael
  • 876
  • 9
  • 29
  • 2
    I get annoyed at the high rep lurkers here who respond to almost every use of raw pointers by saying "Never use raw pointers". But in response to your answer, I have to agree with them. – JSF Jan 26 '16 at 15:48
  • I know there exist smart pointers, but since in his question he used raw pointers, I used them as well. @KarolyHorvath : what do you mean? – Michael Jan 26 '16 at 15:49
  • @Michael Well.. The question didn't use **any** pointers. That was part of the problem. – Algirdas Preidžius Jan 26 '16 at 15:52
  • The question used `->` as if it had used pointers. But it didn't use pointers. Without pointers the `->` wouldn't compile. With pointers the whole problem being asked about wouldn't occur. – JSF Jan 26 '16 at 15:54
  • I just tried this, it worked, thanks! Gonna try the smart pointer one too, but i learned a lot from this post. Thank you very much! – Bert Bijn Jan 26 '16 at 15:56
  • @JSF, who said 'never use raw pointers'? I am the most adamant guy to fight this as a general rule. But **never use dynamic arrays in C++** - this is valid in my view. – SergeyA Jan 26 '16 at 15:56
  • @BertBijn nice to see this is what you asked for. Also, remember to deallocate the arrays, in order to prevent memory leaks. – Michael Jan 26 '16 at 15:58
  • @SergeyA, With my keyboard I don't know how to even start to type the ID of the person who most often says never use raw pointers. But there are a few. I see no reason **never** is more sound for dynamic arrays. But this isn't the place to have that dispute. – JSF Jan 26 '16 at 16:00
  • @BertBijn, do try the version in SergeyA's answer, and **use** that version rather than Michael's version. If you are inexperienced enough to have asked the question, you should trust the experts that the smart pointer is better for you, regardless of any debate between experts of the extent to which smart pointers are or aren't universally better. – JSF Jan 26 '16 at 16:03
-1

So something like:

#include <stdio.h>

class Base {
public:
    virtual void talk() {
        printf("base\n");
    }
};

class Child : public Base {
public:
    void talk()
    {
        printf("child\n");
    }
};

class Child2 : public Base {
public:
    void talk()
    {
        printf("child2\n");
    }
};

int main()
{
    Base* objects[3];
    objects[0] = new Base();
    objects[1] = new Child();
    objects[2] = new Child2();

    for(int i = 0; i < 3; i++) {
        objects[i]->talk();
    }
}
Morten
  • 2,148
  • 2
  • 15
  • 16