Reputation: 1075
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 ?
Upvotes: 3
Views: 88
Reputation: 2914
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
Upvotes: 3
Reputation: 1062
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.
Upvotes: 2
Reputation: 38332
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;
}
};
Upvotes: 1