Search code examples
c++ooppolymorphismabstract-class

How to store different class objects without loosing information


This is my base class where I have method PrintInfo which will be overriden in the child classes.

class Place
{
private:
std::string Name;
int Population;
std::string County;

public:
Place(std::string name,int population,std::string county) 
{
    Name = name;
    Population = population;
    County = county;
}

virtual void PrintInfo()
{
    std::cout << Name << " is with population around " << Population << " and it is in " << County << " county.";
}

};

Below are other two child classes:

class Town : public Place
{
private:
std::string UniversityName;

public:
Town(std::string name, int population, std::string county,std::string universityName) :Place(name, population, county) 
{
    UniversityName = universityName;
};

void PrintInfo()
{
    Place::PrintInfo();

    std::cout << "This town has an university - " << UniversityName << std::endl;
}

};

class Village : public Place
{
private:
std::string SchoolName;

public:
Village(std::string name, int population, std::string county, std::string schoolName) : Place(name,population,county)
{
    SchoolName = schoolName;
};

void PrintInfo() 
{
    Place::PrintInfo();

    std::cout << "Also it is a village and it has a school - " << SchoolName << std::endl;
}

};

So in the main I have the following:

int main()
{

Town town (townName,townPopulation,townCounty, university);
Village village (villageName, villagePopulation, villageCounty, school);

vector<Place> places;

places.push_back(town);
places.push_back(village);

for (auto x : places) 
{
    x.PrintInfo();
}

}

I use vector of type Place because I want to store simultaneously the town object and the village object. When I call the PrintInfo method I want to retrieve the initial information from the base calss and after that to add the information from the child class. At all when I call mehod PrintInfo it shows me only the content in the base class Place. I want to have full access to the information when I call this method.


Solution

  • In your example you are slicing your objects, copying only the base class over to the objects stored in the vector.

    std::vector is for things where you have a variable number of objects at runtime. According to your question, you have a fixed number that is known at design time: One town and one village. I suggest to store it differently:

    template <typename Tup, typename F, std::size_t... I>
    void visitTuple(Tup const& tup, F&& f, std::index_sequence<I...>) {
      (f(std::get<I>(tup)), ...);
    }
    template <typename Tup, typename F>
    void visitTuple(Tup const& tup, F&& f) {
      visitTuple(tup, std::move(f), std::make_index_sequence<std::tuple_size_v<Tup>>{});
    }
    
    std::tuple<Town, Village> places{Town{/*town arguments*/}, Village{/*...*/}};
    visitTuple(places, [](auto const& place) {
      place.PrintInfo();
    });
    

    This is strongly typed and should optimise nicely. You don't even need a common base class or polymorphism.

    Note: This will only work if indeed the amount of places is fixed as you suggest in your OP. If it is, however, determined at runtime, instead use std::vector<std::unique_ptr<Place>> places;.