5

Sorry, if this has been asked before, just learning C++, had tried to search for it but not sure what the keyword is.

would it possible to do this?

class Car {
   public:
      void addColor(string c) {
          color = c;
      }

   private:
      string color;
}

class Honda:public Car {}
class Toyota:public Car {}

int main() {
    vector<Car> v;

    Honda *car1 = new Honda();
    car1.addColor("green");

    Toyota *car2 = new Toyota();
    car2.addColor("blue");

    v.push_back(car1);
    v.push_back(car2);

    for (int i = 0; i < v.size(); i++) {
        cout << v[i].color << endl; // should output green, blue
    }

}

if it's possible, what is the most right/effective way to do it?

EDIT 1

wow, thank you everybody!

badcoder
  • 191
  • 3
  • 13
  • short: yes. If you can handle everything with interface functions you are fine. If you need one function only in one derived class you will most likely need RTTI ( downcast in the foreach loop ) – Najzero Jun 26 '13 at 11:56
  • For one thing, color is a private variable. You'll have get the value some other way – Daniel Jun 26 '13 at 11:56
  • You will need a container that holds (smart) pointers to `Car`, not `Car` obejcts as you have right now. – juanchopanza Jun 26 '13 at 11:58
  • @juanchopanza Smart pointers are definitely not necessary here ! – Jerska Jun 26 '13 at 12:04
  • @Jerska Right, neither is `new`. – juanchopanza Jun 26 '13 at 12:08
  • @juanchopanza Well, actually yes it is. Because subclasses may have a different size from the mother class that cannot be resolved statically. So yes, it needs to be stored in the vector as pointers. (Actually, you could always dereference you local variables, but hey, isn't a new just more explicit for the example ?) – Jerska Jun 26 '13 at 12:10
  • @Jerska no it is not necessary to use `new`, because everything is being created and used in `main`, so you can populate the vector with the addresses of objects of the derived types. *If3 new is needed, then you should prefer using smart pointers. – juanchopanza Jun 26 '13 at 12:13

3 Answers3

2

your vector always hold the base type, Car, sliced. Look up for 'polymorphic STL collection' 'polymorphic vector' or like to see how to store the derived classes.

here is an example

Community
  • 1
  • 1
Balog Pal
  • 16,195
  • 2
  • 23
  • 37
1

There are two ways to handle this. Say we have the following class definitions:

#include <string>
class Car {
   public:
      Car(const std::string& color) : color(color) {}
      virtual ~Car() {}

      std::string color;
};

class Honda:public Car {};
class Toyota:public Car {};

Note I removed the setter and just made the member public. You may or may not want this, but for this example, it doesn't matter. Here is a way by allocating everything on the stack, and taking the address of these objects. This is fine in this example case (car1 and car2 don't need to outlive the main function). In real code this may not be true (i.e. the objects may need to outlive the function in which they are created, see further below):

#include <iostream>
#include <vector>

int main() {
    Honda car1("green");
    Toyota car2("blue");
    std::vector<Car*> cars; // vector of non-owning pointers

    v.push_back(&car1);
    v.push_back(&car2);

    for(auto& car : cars) {
        std::cout << car.color << "\n";
    }
}

Alternatively, allocate your objects on the heap:

int main() {
    std::vector<std::unique_ptr<Car>> cars; // vector of owning pointers

    v.emplace_back(new Honda("green"));
    v.push_back(new Toyota("blue"));

    for(auto& carptr : cars) {
        std::cout << carptr->color << "\n";
    }
}
rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • thanks for the reply, it doesnt seemed to compile though. https://dl.dropboxusercontent.com/u/604317/Screen%20Shot%202013-06-27%20at%2012.34.11.png or am i missing something? – badcoder Jun 27 '13 at 03:36
0

You were on the right way, there were just little things to fix :

  • Add a getter to the base class (Car);
  • Change the vector type (to a vector<Car*>);
  • Replace a.b by a->b when needed;
  • Fix missing semi-colon after classes definitions.

And here you go :

#include <iostream>
#include <vector>

using namespace std;

class Car {
   public:
      virtual ~Car ();
      void addColor(string c) {
          color = c;
      }

      string getColor () {
          return color;
      }

   private:
      string color;
};

class Honda:public Car {};
class Toyota:public Car {};

int main() {
    vector<Car*> v;

    Honda car1;
    car1.addColor("green");

    Toyota car2;
    car2.addColor("blue");

    v.push_back(&car1);
    v.push_back(&car2);

    for (int i = 0; i < v.size(); i++) {
        cout << v[i]->getColor () << endl; // should output green, blue
    }
}

By the way, if you want your subclasses to have their own methods to manipulate the color, just declare the methods as virtual in the car class, and you can redefine it in subclasses.

Another little point. You cannot make your vector be a vector<Car>. Because subclasses might not have the same size as the mother class (Imagine adding a int appeal; to your Honda class), because a vector can only store elements with the same size.

Jerska
  • 11,722
  • 4
  • 35
  • 54
  • This leaks memory though. In C++11, make it a vector>. – Sebastian Redl Jun 26 '13 at 12:19
  • Even if you add `delete`s for `car1` and `car2`, you'd still leak memory; there's no virtual destructor. – rubenvb Jun 26 '13 at 12:21
  • 1
    Are you serious about the leaks ? The op was asking explanations on how methods can be dynamically called, and you're arguing on how would be the best way to avoid leaks ? – Jerska Jun 26 '13 at 12:26
  • 2
    @Jerska: yes. Code needs to be correct. For that, you have my downvote (among other things). – rubenvb Jun 26 '13 at 12:28
  • @rubenvb Now I'm using static variables. Did that change anything, except maybe be confusing because of the dereferencement of the variables ? Thanks for not making a point here. – Jerska Jun 26 '13 at 12:38
  • come on guys, this vector stores non-owning pointers and is okay as the objects sit well in main() and will be destroyed on their own. Even without help of a virtual dtor. It demonstrates the concept under question. – Balog Pal Jun 26 '13 at 12:51
  • 2
    @BalogPal initially it was all dynamically allocated objects that were not being destroyed. Not a good example to set to newcomers. – juanchopanza Jun 26 '13 at 13:17
  • Either it is on the heap or on the stack, everything is cleaned when your program returns. But whatever, I'm not going to argue any longer. – Jerska Jun 26 '13 at 13:30
  • thanks for the reply, this one works! https://dl.dropboxusercontent.com/u/604317/Screen%20Shot%202013-06-27%20at%2013.39.58.png but based on the arguments is not very effective, i have so much to learn :( – badcoder Jun 27 '13 at 04:41
  • @badcoder The discussion wasn't about effectiveness, just about how the memory would be handled. It will be actually faster than using an unique pointer or a shared pointer, because they are intermediary objects that need to be constructed and destroyed. But these two things are made to make you not preoccupy about deleting them. – Jerska Jun 27 '13 at 04:48