1

Well, Hospital is the class which has vector of patients. FemaleIn, FemaleOut, MaleIn, MaleOut are derived classes from patients(Base class). Those classes have toString function(method). What I am trying to do is, in display method in Hospital class, I just want to display only in case of Outpatient which is parent class of FemaleOut and Maleout or Inpatient which is parent class of FemaleIn and MaleIn. From what I am thinking to call only specific method from, for example, Outpatient, I will have to know which objects in which index of vector for automatically. Is there any idea to call only toString for specific class which is, for example, FemaleIn and MaleIn where parent class is Inpatient. Thank you for your any help or suggestion.

void Hospital::determinePatientType()
{
    int selection;
    cout << endl;
    cout << "What is the patient type?" << endl;
    cout << "1. Female Inpatient" << endl;
    cout << "2. Female Outpatient" << endl;
    cout << "3. Male Inpatient" << endl;
    cout << "4. Male Outpatient" << endl;
    cout << endl;
    cin >> selection;

    switch(selection)
    {
    case 1:
        patients.push_back(new FemaleIn());
        cout << patients.back() << endl;
        patients[totalPatients]->enterPatientData();
        totalPatients++;
        break;
    case 2:
        patients.push_back(new FemaleOut());
        cout << patients.back() << endl;
        patients[totalPatients]->enterPatientData();
        totalPatients++;
        break;
    case 3:
        patients.push_back(new MaleIn());
        cout << patients.back() << endl;
        patients[totalPatients]->enterPatientData();
        totalPatients++;
        break;
    case 4:
        patients.push_back(new MaleOut());
        cout << patients.back() << endl;
        patients[totalPatients]->enterPatientData();
        totalPatients++;
        break;
    default:
        return;
    }

}

void Hospital::display(string type)
{


        cout << "Patient Name     Spouse Name    Sex    Patient Type    Unit/Appt. Date    Diagnosis" << endl;
        cout << "===================================================================================" << endl;

        if(type=="All")
        {
            for(int i=0;i<patients.size();i++)
            {
                patients[i]->toString();
            }

        }
        else if(type=="Outpatient")
        {
            for(int i=0;i<patients.size();i++)
            {
                patients[i]->toString();
            }
        }
        else
        {
            for(int i=0;i<patients.size();i++)
            {
                patients[i]->toString();
            }
        }

}
user2807083
  • 2,962
  • 4
  • 29
  • 37
성기덕
  • 43
  • 1
  • 7

2 Answers2

3

I think this question might be similar to How do I check if an object's type is a particular subclass in C++? .

I would propose something like:

Class Patient{
    virtual bool display(string filter);
};
Class OutPatient : Patient {
    bool display(string filter) override;
};
bool OutPatient::display(string filter) {
    if (filter != "OutPatient")
        return false;
    //Do stuff
    return true;
}
Class InPatient : Patient {
    bool display(string filter) override;
};
// You could just make this the default definition on display on Patient
bool InPatient::display(string filter) {
    return false;
}

And then:

void Hospital::display(string type)
{
    for(auto& patient: patients)
        patient->display(type);
}
Nicolás Abram
  • 333
  • 3
  • 12
0

As quick and dirty way you can use dynamic_cast to certain class pointer to detect whether given instance is of that class:

    if (type == "Outpatient")
    {
        for(int i=0; i<patients.size(); ++i)
        {
            // try to cast parent class pointer to one of child class
            // if one is pointer to that child class p is not nullptr
            // otherwise p is nullptr
            Outpatient * p = dynamic_cast<Outpatient *>(patients[i]);

            if (p) {
                p->toString();
            }
        }
    }

For clean way you could use Visitor pattern

Visitor pattern implementation:

#include <iostream>
#include <vector>
#include <string>
#include <functional>
#include <utility>

class AbstractDirectionPatientsDispatcher;
class AbstractGenderPatientDispatcher;

class Patient
{
public:
    virtual void accept(AbstractDirectionPatientsDispatcher &dispatcher) = 0;
    virtual void accept(AbstractGenderPatientDispatcher &dispatcher) = 0;

    std::string name;
};

class InPatient;
class OutPatient;

class AbstractDirectionPatientsDispatcher {
public:
    virtual void dispatch(InPatient &patient) = 0;
    virtual void dispatch(OutPatient &patient) = 0;
};

class FemalePatient;
class MalePatient;

class AbstractGenderPatientDispatcher {
public:
    virtual void dispatch(FemalePatient &patient) = 0;
    virtual void dispatch(MalePatient &patient) = 0;
};

template <typename PatientClass, typename Dispatcher>
class CRTPDispatchApplier : virtual public Patient
{
public:
    void accept(Dispatcher &dispatcher) override {
        dispatcher.dispatch(static_cast<PatientClass &>(*this));
    }
};

class InPatient : public CRTPDispatchApplier<InPatient, AbstractDirectionPatientsDispatcher>
{
};

class OutPatient : public CRTPDispatchApplier<OutPatient, AbstractDirectionPatientsDispatcher>
{
};

class FemalePatient : public CRTPDispatchApplier<FemalePatient, AbstractGenderPatientDispatcher>
{
};

class MalePatient : public CRTPDispatchApplier<MalePatient, AbstractGenderPatientDispatcher>
{
};


class InFemale : public FemalePatient, public InPatient
{
};

class OutFemale : public FemalePatient, public OutPatient
{
};

class InMale : public MalePatient, public InPatient
{
};

class OutMale : public MalePatient, public OutPatient
{
};

class DummyDirectionDispatecher : public AbstractDirectionPatientsDispatcher
{
public:
    void dispatch(InPatient & ) override {
    }

    void dispatch(OutPatient & ) override {
    }
};

class DummyGenderDispatcher : public AbstractGenderPatientDispatcher
{
public:
    void dispatch(FemalePatient &) override {
    }

    void dispatch(MalePatient &) override {
    }
};

template <typename Direction>
class DispatchByDirection : public DummyDirectionDispatecher
{
public:
    DispatchByDirection(std::function<void(Direction &)> action) :
        m_action(std::move(action))
    {}

    void dispatch(Direction & p) override {
        m_action(p);
    }

private:
    std::function<void(Direction &)> m_action;
};

template <typename Gender>
class DispatchByGender : public DummyGenderDispatcher
{
public:
    DispatchByGender(std::function<void(Gender &)> action) :
        m_action(std::move(action))
    {}

    void dispatch(Gender & p) override {
        m_action(p);
    }

private:
    std::function<void(Gender &)> m_action;
};

int main() {
    InFemale f1;
    OutFemale f2;
    InMale m1;
    OutMale m2;
    f1.name = "Eve";
    f2.name = "Alice";
    m1.name = "Bob";
    m2.name = "Charlie";

    std::vector<Patient *> patients;
    patients.push_back(&f1);
    patients.push_back(&f2);
    patients.push_back(&m1);
    patients.push_back(&m2);

    DispatchByDirection<InPatient> print_in_patients{[](InPatient &patient){
        std::cout << "in: " << patient.name << std::endl;
    }};

    for (auto p : patients) {
        p->accept(print_in_patients);
    }
    std::cout << std::endl;

    DispatchByDirection<OutPatient> print_out_patients{[](OutPatient &patient) {
        std::cout << "out: " << patient.name << std::endl;
    }};

    for (auto p : patients) {
        p->accept(print_out_patients);
    }
    std::cout << std::endl;

    DispatchByGender<FemalePatient> print_female{[](FemalePatient &patient) {
        std::cout << "female: " << patient.name << std::endl;
    }};

    for (auto p : patients) {
        p->accept(print_female);
    }
    std::cout << std::endl;

    DispatchByGender<MalePatient> print_male{[](MalePatient &patient) {
        std::cout << "male: " << patient.name << std::endl;
    }};

    for (auto p : patients) {
        p->accept(print_male);
    }
    std::cout << std::endl;
}
user2807083
  • 2,962
  • 4
  • 29
  • 37
  • Thank you so much, it was so helpful ! – 성기덕 Mar 19 '18 at 15:03
  • @성기덕 Just FYI. This is a *very* bad method. Don't do this. It will work, like hammering a wood screw into a board will work, but... – n. m. could be an AI Mar 19 '18 at 15:18
  • @n.m. you are right, but good way is very complicated, especially for beginner – user2807083 Mar 19 '18 at 15:22
  • @user2807083 just use a bog standard virtual function. – n. m. could be an AI Mar 19 '18 at 15:28
  • @n.m. not really, virtual function can do specific things for each class, but can't conditionally either do or don't – user2807083 Mar 19 '18 at 15:30
  • 1
    @user2807083 Sure a virtual function can do something for some class and nothing for another class. There's no prohibition against `{}` function body. But this is not even needed here, a simple `virtual string getType()` or better `bool isOut()` is enough. – n. m. could be an AI Mar 19 '18 at 15:34
  • `virtual string getType()` will do nearly the same thing as `dynamic_cast`. It looks more clear, but also more error-prone, no one is safe to forget replace string literal in `return "some";` e.g. while copypasting – user2807083 Mar 19 '18 at 15:40
  • 1
    "will do nearly the same thing as dynamic_cast" — no, not really. Dynamic cast forces your clients to know too much about your implementation hierarchy. A virtual function, even if it's ostensibly doing things parallel to said hierarchy, does not. Tomorrow you will want to redesign your hierarchy and have just one patient class with InOut and Gender data members, what's your next action? Rewrite all clients that use dynamic cast? A virtual function can keep exactly the same interface. – n. m. could be an AI Mar 19 '18 at 18:14
  • @n.m. ok, you've convinced me, `dynamic_cast` is bad solution – user2807083 Mar 20 '18 at 09:19
  • @n.m. and what do you think about my second solution? – user2807083 Mar 20 '18 at 09:21
  • Visitor is not much better than dynamic-cast in client code, since if the hierarchy changes, you still need to rewrite the visitors. It gives better isolation though so I would prefer it over naked dynamic cast. – n. m. could be an AI Mar 20 '18 at 09:28