【问题标题】:How to check which objects in vector in C++如何在 C++ 中检查向量中的哪些对象
【发布时间】:2018-03-19 14:31:26
【问题描述】:

嗯,Hospital 是具有患者向量的类。 FemaleInFemaleOutMaleInMaleOut 是患者的派生类(基类)。这些类有toString 函数(方法)。我想做的是,在Hospital 类中的display 方法中,我只想显示Outpatient 的情况,这是FemaleOutMaleout 的父类或Inpatient 这是父类FemaleInMaleIn 的类。根据我的想法,仅从 Outpatient 调用特定方法,我将不得不知道哪些对象在向量的哪个索引中自动用于。有什么想法只为特定类调用toString,例如FemaleInMaleIn,其中父类是Inpatient。感谢您的任何帮助或建议。

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

}

【问题讨论】:

  • 问题是什么?
  • 你能否分享一个更详细的代码sn-p来捕捉你的疑惑
  • 不要派生这 4 个类。仅使用基类并在其中添加 2 个字段:性别和类型。打印前在循环中检查它们。
  • 为每个派生类创建一个getType() 方法并查询if (patients[i]-&gt;getType() == type) patients[i]-&gt;toString();

标签: c++ inheritance vector base


【解决方案1】:

我认为这个问题可能类似于How do I check if an object's type is a particular subclass in C++?

我会提出类似的建议:

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

然后:

void Hospital::display(string type)
{
    for(auto& patient: patients)
        patient->display(type);
}

【讨论】:

    【解决方案2】:

    您可以使用dynamic_cast 指向某个类指针来检测给定实例是否属于该类,这是一种快速而肮脏的方式:

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

    对于干净的方式,您可以使用Visitor pattern

    访问者模式实现:

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

    【讨论】:

    • 非常感谢,它很有帮助!
    • @성기덕 仅供参考。这是一个非常糟糕的方法。不要这样做。它会起作用,就像将木螺钉锤入木板一样会起作用,但是......
    • @n.m.你是对的,但是好的方法很复杂,尤其是对于初学者
    • @user2807083 当然,虚函数可以为某个类做点什么,而对另一个类什么也做不了。没有禁止{} 函数体。但是这里甚至不需要,一个简单的virtual string getType() 或者更好的bool isOut() 就足够了。
    • "将做几乎与 dynamic_cast 相同的事情" — 不,不是真的。动态转换迫使您的客户过多地了解您的实施层次结构。一个虚函数,即使它表面上做的事情与所说的层次结构平行,也不是。明天您将想要重新设计您的层次结构,并且只有一个具有 InOut 和 Gender 数据成员的患者类,您的下一步行动是什么?重写所有使用动态转换的客户端?一个虚函数可以保持完全相同的接口。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多