map of derived classes - c++

I have a base class
class Person{
public:
Person(string name , int age ){
this -> name = name;
this -> age = age;
}
virtual void getInfo(){
cout << "Person " << name << " " << age;
}
void add(string name , const Person & b){
a[name] = b
}
protected:
string name;
int age;
map<string , Person > a;
};
That contains map of object type Person. I want to push various derived classes into that map e.g
Derived class
class Kid : public Person{
public:
Kid(string name, int age):Person(name,age){};
virtual void getInfo( ){
cout << "Kid " << name << " " << age;
}
};
I want add method of Person class to bahave such as
Person one("John",25);
one.add("Suzie",15);
Which fails. I know i can remake the code using pointers e.g
map<string , Person*> a
void add( string name , Person *b){
a[name] = b;
}
Person one("John",25);
one.add(new Kid("Suzie",15))
But is there a way how to achieve it without using pointers?

No, you can't obtain polymorphism without using references or pointers.
The issue is easily understood by thinking that a non pointer object requires to store the whole class data (including the vtable).
This means that a map<string, person> will store somewhere person instances in a sizeof(person) slot.
But a sizeof(person) can't contain enough data to store additional information of subclasses of person. This leads to object slicing.

your original design ends up recursing infinitely. You need a polymorphic map, but do you need it to be a member of the class??
Take a look at this question Can a c++ class include itself as an attribute?

Related

C++ : Access of a child member from a parent class

Assuming I have this class below : (I minimized the program as much as I could and deleted the private members and functions that are not related to the issue ).
class CBookings
{
public:
CBookings() = default;
private:
std::vector<CPerson *>Persons;
};
Where CPerson is a parent class :
class CPerson
{
public:
CPerson() = default;
friend class CBookings;
protected:
std::string Name;
};
and CStudent the child of CPerson :
class CStudent : public CPerson
{
public:
CStudent() = default;
private:
unsigned int MatriculationNr;
};
In my program I did a load function where I extracted all the names and their MatricualionNrs from a file and put them into the vector Persons using this method :
if (Line.compare("<student>") == 0)
{
CStudent *S1 = new CStudent();
S1->load(src); //Load function is missing in class but ignore it
Persons.push_back(S1);
}
Now if I want to make a print() function to print the names and their MatricualionNrs.
How can I have access to the child member in this case ? I know that printing the Name of CPerson will require me to add CBookings as a friend class to CPerson but how about the MatriculationNr ?
void CBookings::print()
{
for (int i = 0 ; i < Persons.size() ; i++)
{
cout << Persons[i]->Name << " " << (...MatriculationNr??.) << endl;
}
Not really giving you access to child member, but this is a more OOP approach.
If the only thing you were trying to do is to print the different types of Person classes, then a more proper way of doing it is to define a virtual print function in Person class, then override print function in each child classes, and call person->print() in your Booking class.
In your Person class:
class CPerson
{
public:
virtual void Print()
{
std::cout << Name << "\n";
}
protected:
std::string Name;
}
In your Student class:
class CStudent
{
public:
void Print()
{
CPerson::Print(); // this will execute the Print() you defined in CPerson
std::cout << MatriculationNr << "\n";
// Or you can also just cout all information from here:
// std::cout << Name << ", " << MatriculationNr << "\n";
}
private:
int MatriculationNr;
}
Then in your Booking class, you just call print() from all Person:
void CBookings::Print()
{
for (int i = 0 ; i < Persons.size() ; i++)
{
Persons[i]->Print();
}
}
By doing this, you also don't need to declare Booking as a friend in Person class.
Edit:
In case you were wondering why you want to do it this way:
The fact you used a vector<Person*> implied that there might be other types of Person included in the vector, such as Staff. If not, then you should have just used vector<Student*> instead.
In the case you might also have Staff in it, then doing something like:
std::cout << Persons[i]->MatriculationNr wouldn't make any sense because of course Staff would not have such member in it. Instead, Staff might have a Salary, or whatever in it.
If you keep using the friend class to access private members, you would also need to check each Person's type, if they are a Student or a Staff, then call different cout function based on that.
This becomes tedious if you have many different children types, and your Booking::Print() just becomes a huge if - else if - else if block. And you have to update Booking every time you either change the members of your Person classes, or add another child class to Person.
By having overridden Print() function in your children classes, you don't need to do anything to Booking::Print(), they would all use the same person->Print() from your Booking class.
You cannot access the members of CStudent unless you have a CStudent* pointer.
If your base class CPerson has at least one virtual method, you can use dynamic_cast to safely get a pointer to the actual child class. If the pointer does not point to the proper child class you'll receive a nullptr.
CStudent* pStudent = dynamic_cast<CStudent*>(Persons[i]);
if (pStudent)
{
cout << pStudent->Name << " " << pStudent->MatriculationNr << endl;
}
Doing things this way can be a bad code smell, because it bypasses the principle that a class should be responsible for its own actions. It can also get cumbersome as the number of child classes grows or the number of exceptional member accesses increases - that can lead to bugs.

Storing heterogeanous class type in a variable

I'm a beginner with c++ :), I simplified my problem to this:
I have a class Person
class Person{
string name;}
And another class Student that inherits Person
class Student : public Person{
string schoolName;}
And then I have a class Library that must have a different comportement depending on the input
class Library{
void checkBeforeEntry(Person* p){
cout << "You must be a student to enter" << endl;}
void checkBeforeEntry(Student* s){
cout << "You can enter" << endl;}}
At some point in my programm I'm storing a person like that: Person* guy;
because at that point I don't know yet if he is a simple person or a student.
But due to that I'm "loosing" the information about the real type of the object and I have tried this:
Person *p = new Person();
Student *s = new Student();
Person *g = new Student();
lib.checkBeforeEntry(p);
lib.checkBeforeEntry(s);
lib.checkBeforeEntry(g);
The Output was:
You must be a student to enter
You can enter
You must be a student to enter
But I want the last statement to be "you can enter".
I used a bit of polymorphism before to adapt the comportement of the derived class but here I'm trying to change the comportement of a third party class (library) so the situation is not the same as I am used to. Do you know how to solve this or if I should use another design ?
You can use dynamic_cast to cast downwards which will only succeed (i.e return a non nullptr value) if the runtime type is correct.
Applied to your situation:
void checkBeforeEntry(Person* p){
if (dynamic_cast<Student*>(p)) {
std::cout << "You can enter" << std::endl;
} else {
std::cout << "Only students can enter" << std::endl;
}
}
This has the downside however, that it requires Runtime Type Information (RTTI) to be enabled and might be quite costly (as usual implementations look up and check RTTI informations stored right next to the vftable). Also it requires you to specify specific types (imagine how adding Professor, Librarian, etc. classes would bloat the above code)
An arguably better approach can be to declare a virtual bool isStudent() or virtual bool canEnterLibrary() on Person
What you are using here is called a static-polymorphism. Which means that the type checking is taking place at compile-time and not run-time. I.e. the type of the pointers is deciding the type of the objects and hence the version of the overloaded function checkBeforeEntry() to be called.
To achieve what you want, and in a simplest way with the minimal impact on the existing code you have, I think the following can be the best.
class Person {
public:
string name;
virtual bool passLibrary() const {return false;}
virtual ~Person();
};
class Student: public Person {
public:
string schoolName;
bool passLibrary() const override {return true;}
virtual ~Student();
};
class Library {
public:
void checkBeforeEntry(const Person *p) const {
if (p->passLibrary()) {
cout << "You can enter" << endl;
} else {
cout << "You must be a student to enter" << endl;
}
}
};
So here the function passLibrary() is a virtual function, which means it'll use the dynamic-polymorphism, i.e. check the current object type at run-time, and each of your classes Person and Student will provide their own implementation, which will be used by the class Library to distinguish easily between Person and Student objects.
I hope this was clear enough.
class Person {
string name;
public:
virtual ~Person() = default;
virtual bool isStudent() const { return false; }
};
class Student : public Person {
string schoolName;
public:
bool isStudent() const override { return true; }
};
class Library {
void checkBeforeEntry(Person* p) {
if (!p->isStudent())
cout << "You must be a student to enter" << endl;
else
cout << "You can enter" << endl;
}
};

How to use a member function from a parent class with the same name (via this->)?

Heres the gist of my program:
I have a base class called Person. It has a child called President. I am trying to create a "printInfo" function in the President class that prints all of its attributes from both classes.
The simplest change was to simply differentiate the functions by changing the names, but I was wondering if there was a way to do this without changing them.
(The code below just includes the relevant parts, I left out a bunch of other member functions to make it easier to read)
class Person : public Address {
public:
void printInfo(); // this prints the name and birthday
private:
string fname, lname, sex;
int month, day, year;
};
class President : public Person {
private:
int term;
public:
void printInfo(); // this prints term
};
void President::printInfo() {
cout << term << " : ";
this->printInfo(); //need this to use the person version of itself
};
What I want:
1 : George Washington ....
Actual Result:
1 : 1 : 1 : ....
You can call the member function of base class by adding Person:: prefix. e.g.
void President::printInfo() {
cout << term << " : ";
Person::printInfo();
};
BTW: It's better to make printInfo and the destructor of Person virtual.

how to access elements of a derived class through a parent class in c++?

class game_list
{
public:
string name;
float price;
string platform;
string console;
string conditin;
bool is_portable;
};
class catridgeClass:public game_list
{
string N_bits;
bool is_import;
};
game list is dynamically created and a pointer called mainPointer points to that dynamic object. But I am confused on how to access cartridgeClasss elements through the parent class game_list. I already tried mainPointer->N_bits. Seems like it doesnt work that way? Sorry I am just a noob at c++.
To access catridgeClass attributes, you will need a catridgeClass object.
First, you need to correct your class to have public attributes.
class catridgeClass:public game_list
{
public:
string N_bits;
bool is_import;
};
class anotherClass: public game_list
{
public:
string other_member;
};
Than you need to get a catridgeClass object from the caller function:
int main()
{
std::vector<game_list *> games;
games.push_back(new catridgeClass);
games.push_back(new anotherClass);
for(int i=0; i<games.size(); i++)
{
//You will need to get a catridgeClass object to access it's members.
catridgeClass *catridge_ptr = dynamic_cast<catridgeClass *>(games[i]);
//Or to access anotherClass.
anotherClass *another_ptr = dynamic_cast<anotherClass*>(games[i]);
//If the conversion is not possible, dynamic_cast will return a null pointer
if(catridgeClass != NULL)
std::cout << catridge->N_bits << std::endln;
if(anotherClass != NULL)
std::cout << anotherClass->other_member << std::endln;
}
//And of course, you need to avoid a memory leak
for(int i=0; i<games.size(); i++)
delete games[i]
return 0;
}
Keep in mind that it's not a desired design. If you are trying to use polimorphism, is because all that classes share common behaviours. A better approach would be to use interfaces.
Try a virtual method getNBits() = 0; in parent class, and define it in child class.
See: C++ Virtual/Pure Virtual Explained
A parent class has no information about its child class. The only way to do what you want is to either cast like Dory suggested -- which I usually frown upon -- or to create a virtual function in the parent class that the child class redefines.
Why do I frown upon the cast? Most of the time dynamically casting an object to get data from it represents poorly written code. I'm not sure what the rest of your code looks like, but my guess is that there's a better way to write this via shared functionality. For example, let's say what you want to use these items for is displaying string information. In such a case, the best way to write it would be using virtual functions:
class game_list
{
public:
string name;
float price;
string platform;
string console;
string conditin;
bool is_portable;
public virtual void PrintInfo()
{
cout << "name: " << name << ", price: " << price; //etc
}
};
class catridgeClass:public game_list
{
string N_bits;
bool is_import;
public virtual void PrintInfo()
{
game_list::PrintInfo();
cout << ", bits: " << bits << ", is import: " << is_import;
}
};
Now calling mainPointer->PrintInfo() will print the correct information regardless of its underlying type. Much nicer, and it's the "Object-Oriented Way."
try to use dynamic_cast
catridgeClassPtr = dynamic_cast<catridgeClass*>(GameListPtr);
catridgeClassPtr->N_bits;
full info on dynamic_cast:
http://www.cplusplus.com/doc/tutorial/typecasting/

Return a function from multiple derived classes

I have a base class and multiple derived classes from it. Each derived class has a constructor that accepts parameters that were initialized in the base class. All of the constructors are different, however they all accept one common parameter, let's call it Name.
Is there a way for me to display every derived class' name in a shorter way than calling them one after another?
Here's an example. Let's say my base class is Father and my derived classes are Brother, Sister, HalfBrother, HalfSister and this is my driver file:
cout << Brother::Brother().getName() << endl
<< Sister::Sister().getNAme() << endl
<< HalfBrother::HalfBrother().getNAme() << endl
<< HalfSister::HalfSister().getName() << endl;
This will return them fine, but is there a simpler way to do this so that I can get all the names from all the derived classes without having to write them one by one?
You can create a static registry of classes, and populate it from constructors of static members that you insert into classes that you would like to register.
In the header:
class Registration {
static vector<string> registered;
public:
static void showRegistered() {
for (int i = 0 ; i != registered.size() ; i++) {
cout << registered[i] << endl;
}
}
Registration(string name) {
registered.push_back(name);
}
};
In the CPP file:
vector<string> Registration::registered;
With this class in hand, you can do this:
In the headers:
class A {
static Registration _registration;
};
class B {
static Registration _registration;
};
class C {
static Registration _registration;
};
In the CPP files:
Registration A::_registration("quick");
Registration B::_registration("brown");
Registration C::_registration("fox");
This last part is key: declarations of the static _registration variables have a side effect - they insert the name into the vector<string> registered of the Registration class, in no specific order. You can now retrieve the names, print them out, or do whatever you want with them. I added a member-function for printing, but obviously you are not limited by it.
Here is a demo on ideone - it prints
quick
brown
fox
Honestly I am not sure if I understand your question. As said in comment, you should make getName() a method in Father.
class Father {
public:
Father(string name) : m_name(name) {
}
string& getName() {
return m_name;
}
private:
string m_name;
};
class Brother : public Father {
public:
Brother(string name) : Father(name) {
}
};
class Sister : public Father {
public:
Sister(string name) : Father(name) {
}
};
So you can have something like:
vector<Father *> fathers;
Brother brother("...");
Sister sister("....");
father.push_back(&brother);
father.push_back(&sister);
for (vector<Father*>::iterator itr = fathers.begin();
itr != fathers.end();
++itr) {
cout << (*itr)->getName() <<endl;
}