简体   繁体   English

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

[英]Create a vector of base class objects and store derived class objects within

I am trying to create an employee database (Vector of Employees). 我正在尝试创建一个雇员数据库(雇员矢量)。 There are 3 types of employees ie. 有3种类型的员工,即。 employees is the base class and Manager, Engg and Scientist are derived class. 员工是基础类,经理是Engg和Scientist的派生类。 Every employee has first name and last name. 每个员工都有名字和姓氏。 In addition to the name, each of the 3 types of employees have unique stats ie. 除名称外,这3种类型的员工中的每一个都有唯一的统计信息,即。 Manager has number of meetings/week whereas the Engg has work experience and so on. 经理每周有会议次数,而Engg具有工作经验等。

I have a couple of questions 1. Should I upcast the derived objects to the base class or downcast the base class to the derived class? 我有两个问题:1.我应该将派生的对象转换为基类还是将基类转换为派生类? 2. How do I use polymorphism to override methods, since I want the user to add an employee type and based on the type selected the respective entry fields should appear ie. 2.如何使用多态性覆盖方法,因为我希望用户添加员工类型,并且根据所选的类型,应出现相应的输入字段,即。 in case of a Manager, in addition to the first and last names, the program should also ask for meetings/week? 如果是经理,除了名字和姓氏之外,该计划还应该要求每周开会一次?

Here is my Class file 这是我的班级文件

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

Here is the implementation 这是实现

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;

Here is the main 这是主要的

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!

Firstly, if you want to use polymorphism you need to store pointers in your vector. 首先,如果要使用多态,则需要将指针存储在向量中。 As the vector is the sole owner of the employees something like std::vector<std::unique_ptr<Employee>> would be suitable. 由于vector是雇员的唯一所有者,因此类似std::vector<std::unique_ptr<Employee>>方法是合适的。

Edit: I see you have updated the vector to use pointers. 编辑:我看到您已经更新了向量以使用指针。 But you are storing a pointer to a local stack allocated object, eg mEmp . 但是您正在存储一个指向本地堆栈分配对象的指针,例如mEmp This will not work, when the mEmp variable goes out-of-scope at the closing brace the object will be deleted and you will be left with a dangling pointer in your vector that points to a deleted object. mEmp变量在mEmp大括号内超出范围时,这将不起作用,该对象将被删除,并且向量中的悬空指针将指向您删除的对象。 Using this dangling pointer is undefined behaviour. 使用此悬空指针是未定义的行为。 You need to allocate the Manager on the heap using new . 您需要使用new在堆上分配Manager Then the object will not be deleted when the variable goes out-of-scope but you do need to remember to delete the object when you are done. 这样,当变量超出范围时,该对象将不会被删除,但是您确实需要记住在完成操作后删除该对象。 Something like unique_ptr makes this easy. 诸如unique_ptr东西使此操作变得容易。

Regarding your questions: 关于您的问题:

  1. Try to minimize explicit casting, especially downcasting. 尽量减少显式转换,尤其是向下转换。 At the point that you store the Employee in the vector it will be implicitly upcast from the derived class to Employee but other than that there is not much need for casting. 在将Employee存储在向量中的那一刻,它将被隐式地从派生类向上转换为Employee但除此之外,不需要进行强制转换。
  2. You have roughly the right idea when it comes to overriding methods, if you call the virtual printEmp method on an Employee pointer it will call the override in the derived class. 关于覆盖方法,您大概有一个正确的主意,如果在Employee指针上调用虚拟printEmp方法,它将在派生类中调用覆盖。

    If you are happy for the user input to be the responsibility of the Employee classes you could simply add a virtual method that initializes the employee using suitable input from the user. 如果您希望用户输入成为Employee类的职责,则可以简单地添加一个虚拟方法,该方法使用来自用户的适当输入来初始化员工。 But I would be tempted to keep that separate from your domain objects. 但我很想将其与您的域对象分开。 You need a switch statement on the user choice of employee type anyway so polymorphism doesn't gain you much there. 无论如何,您都需要一个关于雇员类型的用户选择的switch语句,因此多态性不会给您带来太多好处。

    If you really want to use polymorphism for the employee creation I would suggest using something like the Abstract Factory pattern. 如果您真的想使用多态来创建员工,我建议您使用类似Abstract Factory模式的方法。

Here is my suggestion anyway: 无论如何,这是我的建议:

#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 现场演示

You may want to store pointers in the vector to avoid slicing, as others mentioned. 正如其他人提到的那样,您可能希望将指针存储在向量中以避免切片。 Then each employee could have their own input method and ask the right questions to initialize themselves (main would not implement that but only call the respective employee's virtual input function). 然后,每个员工可以拥有自己的输入方法,并提出正确的问题来初始化自己(main不会实现该方法,而只会调用各自员工的虚拟输入函数)。 Input and output are conceptually sysmmetrical operations which hints at implementing them symmetrically, ie in this case both as member functions. 输入和输出在概念上是系统操作,它暗示对称地实现它们,即,在这种情况下,它们都作为成员函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将抽象派生类对象存储在基类向量中 - Store abstract derived class objects in base class vector 将派生的 class 对象存储在基础 class 变量中 - Store derived class objects in base class variables 具有派生对象的基类的std :: vector - std::vector of Base class with Derived objects 在基础 class 中创建派生类的对象 - Create objects of derived classes in base class 如何在指向基类对象的指针向量中引用派生对象? - How to reference derived objects in a vector of pointers to base class objects? 从基类对象的向量获取特定派生类的对象 - Getting an object of a specific derived class, from a vector of base class objects 使用基本接口类参数将派生类对象添加到向量 - Adding derived class objects to vector with base interface class parameter 派生类对象在对象向量中覆盖基类的函数 - Derived class object override a function of base class in a vector of objects 制作基类指针的向量并将派生类对象传递给它(多态) - Making a vector of base class pointers and pass Derived class objects to it (Polymorphism) 指向包含基类和派生类 class 对象的指针的向量 - 访问派生类特定变量 - Vector of pointers to base class containing base and derived class objects - accessing derived-class specific variables
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM