创建基类对象的向量并在其中存储派生类对象

时间:2015-01-19 16:59:59

标签: c++ inheritance polymorphism

我正在尝试创建员工数据库(员工矢量)。有3种类型的员工即。员工是基础类,经理,Engg和科学家都是派生类。 每个员工都有名字和姓氏。除了名称之外,3种类型的员工中的每一种都具有独特的统计数据,即。经理有多个会议/周,而Engg有工作经验等等。

我有几个问题 1.我应该将派生对象向上转换为基类还是将基类向下转换为派生类? 2.我如何使用多态来覆盖方法,因为我希望用户添加一个雇员类型,并根据所选的类型显示相应的输入字段,即。如果是经理,除了名字和姓氏外,该计划还应该每周要求会议?

这是我的班级文件

class Employee{
public:
Employee();
 Employee(string fName, string lName, int sal);
virtual void printEmp();
string getFirstName();
string getLastName();

protected:
string m_fName;
string m_lName;
int m_sal;
};


class Manager : public Employee{
public:
Manager();
Manager(string fName, string lName, int sal, int meets, int hols);
void printEmp();


protected:
int m_meets;
int m_hols;
};

这是实施

Employee::Employee(){
m_fName = "Default";
m_lName = "Default";
m_sal = 0;
}


Employee::Employee(string fName, string lName, int sal){
m_fName = fName;
m_lName = lName;
m_sal = sal;
}

void Employee::printEmp(){
cout << "First Name: " << m_fName << endl
    << "Last Name: " << m_lName << endl
    << "Salary: " << m_sal << endl;
}


string Employee::getLastName(){
return m_lName;
}

string Employee::getFirstName(){
return m_fName;
}

Manager::Manager(string fName, string lName, int sal, int meets, int hols) :         Employee(fName, lName, sal), m_meets(meets), m_hols(hols)
{
//empty
}

void Manager::printEmp(){
Employee::printEmp();
cout << "Meets/Week: " << m_meets << endl
    << "Holidays/Year: " << m_hols << endl << endl;

这是主要的

int main(){

    bool exit = false;
    vector<Employee*> dBVector;

    while (!exit){

        cout << "Welcome to Employee Database, Enter an option to continue..." << endl;
        cout << "1) Add an Employee, 2) Delete an Employee, 3) Save Database, 4) Exit" << endl;
        int input;
        cin >> input;

        string fNameInp;
        string lNameInp;
        int salInp;
        string lNameSearch;
        int i; // for loop in Delete employee case
        bool deleted = false;

        switch (input){
        case 1: //Add
            cout << "1) Add a Manager, 2) Add an Engg, 3) Add a Researcher" << endl;
            int empInput;
            cin >> empInput;



            if (empInput == 1){


                cout << "Enter First Name: ";
                cin >> fNameInp;

                cout << "Enter Last Name: ";
                cin >> lNameInp;

                cout << "Enter Salary: ";
                cin >> salInp;

                cout << "Number of meetings/week: ";
                int meetsInp;
                cin >> meetsInp;

                cout << "Number of holidays/year: ";
                int holsInp;
                cin >> holsInp;

                Manager mEmp(fNameInp, lNameInp, salInp, meetsInp, holsInp);
                Employee &emp = mEmp;
                dBVector.push_back(&mEmp);
                dBVector[dBVector.size()-1]->printEmp();

            }

            else if (empInput == 2){
                cout << "Enter First Name: ";
                cin >> fNameInp;

                cout << "Enter Last Name: ";
                cin >> lNameInp;

                cout << "Enter Salary: ";
                cin >> salInp;

                cout << "Cpp Experience (Y/N): ";
                string cppInp;
                cin >> cppInp;

                cout << "Years of experience: ";
                float expInp;
                cin >> expInp;

                cout << "Engg Type (Chem, Mech, IT): ";
                string typInp;
                cin >> typInp;

                Engg eEmp(fNameInp, lNameInp, salInp, cppInp, expInp, typInp);
                Employee &emp = eEmp;
                dBVector.push_back(&eEmp);
                dBVector[dBVector.size() - 1]->printEmp();

            }

            else if (empInput == 3){
                cout << "Enter First Name: ";
                cin >> fNameInp;

                cout << "Enter Last Name: ";
                cin >> lNameInp;

                cout << "Enter Salary: ";
                cin >> salInp;

                cout << "School of PhD: ";
                string schoolInp;
                cin >> schoolInp;

                cout << "Topic of PhD: ";
                string topImp;
                cin >> topImp;

                Researcher rEmp(fNameInp, lNameInp, salInp, schoolInp, topImp);
                Employee &emp = rEmp;
                dBVector.push_back(&rEmp);
                dBVector[dBVector.size() - 1]->printEmp();

            }
            break;

        case 2: // Delete Emp
            for (int x = 0; x < dBVector.size(); x++){
                dBVector[x]->getLastName();
                cout << endl;
            }

            cout << "Input Last name of the employee to delete: " << endl;
            cin >> lNameSearch;
            for (i = 0; i < dBVector.size(); i++){
                if (dBVector[i]->getLastName() == lNameSearch){
                    dBVector.erase(dBVector.begin() + i);
                    cout << dBVector[i]->getFirstName() << "has been deleted from database";
                    deleted = true;
                    break;
                }
            }
            if (deleted == false && i == dBVector.size()){
                cout << "No Employee with Last Name - " << lNameSearch << " exists in Database." << endl;
            }
            else
                break;

        case 3: //save
            cout << "saving..." << endl;
            break;

        case 4: //exit
            exit = true;
            break;
        }
    }
}
Please Help!

2 个答案:

答案 0 :(得分:1)

首先,如果要使用多态,则需要在向量中存储指针。由于向量是员工的唯一所有者,std::vector<std::unique_ptr<Employee>>之类的东西是合适的。

编辑:我发现你已经更新了矢量以使用指针。但是您正在存储指向本地堆栈分配对象的指针,例如mEmp。这不起作用,当mEmp变量在结束括号中超出范围时,对象将被删除,并且您将在向量中留下指向已删除对象的悬空指针。使用此悬空指针是未定义的行为。您需要使用Manager在堆上分配new。然后,当变量超出范围时,不会删除该对象,但是您需要记住在完成后删除该对象。像unique_ptr之类的东西可以让这很容易。

关于你的问题:

  1. 尽量减少显式投射,尤其是向下投射。在将Employee存储在向量中时,它将从派生类隐式向上转换为Employee,但除此之外不需要进行强制转换。
  2. 当涉及到覆盖方法时,你有大致正确的想法,如果你在printEmp指针上调用虚拟Employee方法,它将在派生类中调用覆盖。

    如果您对用户输入是Employee类的责任感到满意,您只需添加一个虚拟方法,使用来自用户的合适输入来初始化员工。但我很想将它与你的域对象分开。无论如何,您需要一个关于员工类型的用户选择的switch语句,因此多态性在那里没有多少收获。

    如果您真的想在员工创建中使用多态,我建议您使用类似抽象工厂模式的东西。

  3. 无论如何,这是我的建议:

    #include <vector>
    #include <string>
    #include <iostream>
    #include <memory>
    
    class Employee {
     public:
      Employee(std::string fName, std::string lName, int sal);
      virtual ~Employee();
    
      virtual void printEmp();
    
     protected:
      std::string m_fName;
      std::string m_lName;
      int m_sal;
    };
    
    class Manager : public Employee {
     public:
      Manager(std::string fName, std::string lName, int sal, int meets, int hols);
      void printEmp() override;
    
     protected:
      int m_meets;
      int m_hols;
    };
    
    Employee::Employee(std::string fName, std::string lName, int sal)
      : m_fName(fName), m_lName(lName), m_sal(sal) {
    }
    
    Employee::~Employee() {
    }
    
    void Employee::printEmp(){
      std::cout << "First Name: " << m_fName << "\n"
                << "Last Name: " << m_lName << "\n"
                << "Salary: " << m_sal << "\n";
    }
    
    Manager::Manager(std::string fName, std::string lName, int sal, int meets, int hols) 
      : Employee(fName, lName, sal), m_meets(meets), m_hols(hols){
    }
    
    void Manager::printEmp(){
      Employee::printEmp();
      std::cout << "Meets/Week: " << m_meets << "\n"
                << "Holidays/Year: " << m_hols << "\n";
    }
    
    std::unique_ptr<Manager> createManager() {
      std::cout << "Enter First Name: ";
      std::string fNameInp;
      std::cin >> fNameInp;
    
      std::cout << "Enter Last Name: ";
      std::string lNameInp;
      std::cin >> lNameInp;
    
      std::cout << "Enter Salary: ";
      int salInp;
      std::cin >> salInp;
    
      std::cout << "Number of meetings/week: ";
      int meetsInp;
      std::cin >> meetsInp;
    
      std::cout << "Number of holidays/year: ";
      int holsInp;
      std::cin >> holsInp;
      std::cout << "\n";
    
      return std::make_unique<Manager>(fNameInp, lNameInp, salInp, meetsInp, holsInp);
    }
    
    std::unique_ptr<Employee> createEmployee() {
      int input;  
      std::cout << "1) Add a Manager, 2) Add an Engg, 3) Add a Researcher\n";
      std::cin >> input;    
      switch (input){
        case 1:
          return createManager();   
        default:
          return nullptr;
      }
    }
    
    int main() {
      std::vector<std::unique_ptr<Employee>> dBVector; 
    
      std::cout << "Welcome to Employee Database, Enter an option to continue...\n";
      std::cout << "1) Add an Employee"
                << ", 2) Delete an Employee"
                << ", 3) Save Database"
                << ", 4) Exit\n";
      int input;
      std::cin >> input;
    
      switch (input){
        case 1:
          dBVector.push_back(createEmployee());
          break;
        default:
          break; // Do nothing
      }
    
      dBVector.at(0)->printEmp();    
    }
    

    Live demo

答案 1 :(得分:0)

您可能希望在向量中存储指针以避免切片,正如其他人提到的那样。然后,每个员工都可以拥有自己的输入法,并要求正确的问题进行初始化(主要不会实现,而只是调用相应员工的虚拟输入功能)。输入和输出是概念上的对称操作,暗示对称地实现它们,即在这种情况下都作为成员函数。