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

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.

Related

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;
}
};

Call derived class non virtual member functions from base class pointer

We know that, derived class members functions can be accessed through a base class pointer in C++ , provided that these member functions have to be virtual. Is there a means to access derived class member functions which are NOT virtual or pure virtual from base class pointer.
i.e. I want to call derived class member functions which are present only in derived class & not in base class through base class pointer. How would I achieve this?
For example, if I design a factory design pattern,
class Vehicle {
public:
virtual void printVehicle() = 0;
static Vehicle* Create(VehicleType type);
};
class TwoWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am two wheeler" << endl;
}
void Some2WheelerONLYSpecificOPeration()
{
}
};
class ThreeWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am three wheeler" << endl;
}
void Some3WheelerONLYSpecificOPeration()
{
}
};
class FourWheeler : public Vehicle {
public:
void printVehicle() {
cout << "I am four wheeler" << endl;
}
void Some4WheelerONLYSpecificOPeration()
{
}
};
// Factory method to create objects of different types.
// Change is required only in this function to create a new object type
Vehicle* Vehicle::Create(VehicleType type) {
if (type == VT_TwoWheeler)
return new TwoWheeler();
else if (type == VT_ThreeWheeler)
return new ThreeWheeler();
else if (type == VT_FourWheeler)
return new FourWheeler();
else return NULL;
}
int main()
{
Vehicle* basePtr = Vehicle::Create(VT_TwoWheeler);
basePtr->Some2WheelerONLYSpecificOPeration(); //HOW TO ACHIEVE THIS CALL
basePtr = Vehicle::Create(VT_ThreeWheeler);
basePtr->Some3WheelerONLYSpecificOPeration(); //HOW TO ACHIEVE THIS CALL
basePtr = Vehicle::Create(VT_FourWheeler);
basePtr->Some4WheelerONLYSpecificOPeration(); // //HOW TO ACHIEVE THIS CALL
}
I want to call derived class member functions which are present only in derived class & not in base class through base class pointer. How would I achieve this ?
You cannot call a non-virtual member function of the derived class with a pointer to the base class.
You'll need a pointer to the derived class. The simplest method is to use dynamic_cast to get a pointer to the derived class, check whether the cast was successful, then call the derived class member function using a derived class pointer.
A better method would be to provide a virtual member function in the base class and implement it in the derived class.
You can do what you want with dynamic_cast, but this will lead to disappointing results at a code review. Instead, I pitch you go the same route you did with printVehicle
class Vehicle
{
public:
// without a virtual destructor you are walking into
// a very bad bug. The wrong destructor may be called.
virtual ~Vehicle()
{
}
virtual void printVehicle() = 0;
// Specific stuff that all children must provide
virtual void doTypeSpecificStuff() = 0;
// this is actually a bit of a ideological weird. I'm not sure I can call
// it a flaw. By making this factory function a member of Vehicle, Vehicle
// must now know its children. If this is the case, the VehicleType enum
// should probably be a member of Vehicle, but personally I think this
// factory should be a totally free function.
static Vehicle* Create(VehicleType type);
};
class TwoWheeler: public Vehicle
{
public:
void printVehicle()
{
cout << "I am two wheeler" << endl;
}
void doTypeSpecificStuff()
{
cout << "Doing two wheeler stuff" << endl;
}
};
Leaving out the other two classes and Vehicle::Create to save space.
int main()
{
Vehicle* basePtr = Vehicle::Create(VT_TwoWheeler);
basePtr->doTypeSpecificStuff(); //HOW TO ACHIEVE THIS CALL
// leaking memory here, so
delete basePtr;
// but also look into std::unique_ptr. Much better suited to this behaviour
}
In fact, let's act on on that final comment about std::unique_ptr right now. A unique_ptr manages your dynamic allocations for you so you don't have to clutter up your code with deletes and run the risk of missing one or deleteing too soon. The unique_ptr's pointer is valid for as long as the unique_ptr is in scope. If you can compile, the pointer is good unless you done something silly like never point it at anything or manually remove the pointer.
And while we're at it, let's eliminate my earlier concerns about vehicle::Create.
First we define a free function to replace Create and return a unique_ptr. Since I hate to have to have if (ptr != NULL) checks all through my code to make sure an object really was created, let's also make a big stink about it when we can't match the provided vehicle type with class by throwing an exception.
And rather than a chain of if-else ifs we'll use a somewhat more elegant switch statement.
std::unique_ptr<Vehicle> SmarterVehicleFactory(VehicleType type)
{
switch (type)
{
case VT_TwoWheeler:
return std::make_unique<TwoWheeler>();
case VT_ThreeWheeler:
return std::make_unique<ThreeWheeler>();
case VT_FourWheeler:
return std::make_unique<FourWheeler>();
default:
throw std::runtime_error("Invalid Vehicle type");
}
}
And then we'll use this new function
int main()
{
try
{
std::unique_ptr<Vehicle> basePtr = SmarterVehicleFactory(VT_TwoWheeler);
basePtr->doTypeSpecificStuff();
basePtr = SmarterVehicleFactory(VT_ThreeWheeler);
// unique_ptr freed the TwoWheeler for us.
basePtr->doTypeSpecificStuff();
basePtr = SmarterVehicleFactory(VT_FourWheeler);
basePtr->doTypeSpecificStuff();
// just for laughs we will ask for a FiveWheeler, which we have not yet
// fully implemented
basePtr = SmarterVehicleFactory(VT_FiveWheeler); // will throw exception
basePtr->doTypeSpecificStuff(); // will not be executed
}
catch (const std::exception & exc)
{
cerr << "Rats! Something bad happened: " << exc.what();
// basePtr will be unmodified and still pointing to a FourWheeler
}
} // basePtr will go out of scope here and clean up our memory for us.
The beauty of this approach is no class knows anything about any other class. You can put Vehicle in a header with the SmarterVehicleFactory prototype and the list of vehicle types and hide everything else. The user sees nothing. Everybody is kept in the dark.
Why is that good? Because now you can change any of the above classes, except the Vehicle interface class, without having any effect on any of the other classes. This makes your code easier to maintain and debug.
I'm trying to find the best way to use polymorphism without using inheritance, because I want to avoid virtual calls. I was looking for a way to improve what I currently have (with no avail) and I stumbled on this question. This is the best I can do so far:
template<class VehicleDetails>
class Vehicle {
VehicleDetails details;
public:
VehicleDetails& getDetails() {
return details;
}
const VehicleDetails& getDetails() const {
return details;
}
void printDetails() const {
details.printDetails();
}
}
class TwoWheeler {
public:
void printDetails() const {
cout << "I am two wheeler" << endl;
}
void specificTwoWheelerMethod() const {
cout << "I am specific functionality" << endl;
}
}
Then you use it as such:
Vehicle<TwoWheeler> vehicle;
vehicle.printDetails(); // prints "I am two wheeler"
Unfortunately this complicates things. Now every class/struct or function that takes a vehicle must be templated, unless you know the type of vehicle.
template<class VehicleDetails>
void doGeneralVehicleThings(const Vehicle<VehicleDetails>& vehicle) {
// ...
}
On the plus side when you do know the type you can access specific functionality via the getDetails() method without any casting or runtime overhead involved:
void doTwoWheelerThings(const Vehicle<TwoWheeler>& twoWheelerVehicle) {
twoWheelerVehicle.getDetails().specificTwoWheelerMethod(); // prints "I am specific functionality"
}

C++ array of the same class hierarchy

According to my book, if I want to make an array of objects that are not in the same class but in the same class hierarchy, I need to use pointers:
class text
{
public:
void write(string text);
void show();
private:
string texte;
};
void text::write(string text)
{
texte = text;
}
void text::show()
{
cout << texte;
}
class text_with_stars : public text
{
public:
void show();
};
void text_with_stars::show()
{
cout << "*";
text::show();
cout << "*";
}
int main()
{
text* array[2];
array[0] = new text;
array[0]->write("Hello");
text_with_stars* pointer = new text_with_stars;
pointer->write("Hi");
array[1] = pointer;
for (int i=0;i<2;i++)
{
array[i]->show();
}
return 0;
}
But when I do this, the output is "HelloHi" meaning that the second object used the show version that is from text and not from text_with_stars, but I made it exactly the same way that the book described. What Is the problem??
Here is what is written in the book:
Question* quiz[2];
quiz[0] = new Question;
quiz[0]->set_text("Who was the inventor of C++?");
quiz[0]->set_answer("Bjarne Stroustrup");
ChoiceQuestion* cq_pointer = new ChoiceQuestion;
cq_pointer->set_text("In which country was the inventor of C++ born?")
cq_pointer->add_choice("Australia",false);
...
quiz[1] = cq_pointer;
The chapter right next to the one I was reading is about virtual functions and it explains that the system will always use the member functions of Question instead of ChoiceQuestion, looks like I should read more before asking questions on internet!
void show()
needs to be virtual in the base class if you want to use methods from derived classes from base class pointers
The reason this is happening is because the function you are calling is non-virtual.
Let's say we have a class Parent and a class Child inheriting from the parent:
class Parent {
public:
void f() {
cout << "Parent::f()" << endl;
}
};
class Child : public Parent {
public:
void f() {
cout << "Child::f()" << endl;
}
};
Now, let's make a pointer to a Parent and store a Child in it (polymorphism):
Parent *ptr = new Child;
ptr->f();
At this point, the compiler sees ptr having type Parent* and determines that the function to be called is Parent::f().
In order to call Child::f() when dealing with polymorphism? The Parent::f() must be defined virtual. The compiler then generates code to check at run-time the value that is stored in memory to call the appropriate (child) function.
In short: ONLY when a function is virtual and is called on a pointer or reference, a memory lookup is made to determine the actual type at that point in memory. Otherwise it is not.

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;
}