创建基础 class 对象的向量并将派生的 class 对象存储在其中
Create a vector of base class objects and store derived class objects within
我正在尝试创建一个员工数据库(员工向量)。有 3 种类型的员工,即。 employees 是基础 class,Manager、Engg 和 Scientist 是派生的 class。
每个员工都有名字和姓氏。除了名字之外,这 3 种类型的员工中的每一种都有独特的统计数据,即。经理有人数meetings/week 而工程师有工作经验等等。
我有几个问题
1. 我应该将派生对象向上转换为基数 class 还是将基数 class 向下转换为派生对象 class?
2. 我如何使用多态性来覆盖方法,因为我希望用户添加员工类型,并根据所选的类型显示相应的输入字段,即。如果是经理,除了名字和姓氏之外,程序还应该要求 meetings/week?
这是我的 Class 文件
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!
您可能希望在向量中存储指针以避免切片,正如其他人提到的那样。然后每个员工都可以有自己的输入法,并提出正确的问题来初始化自己(main 不会实现它,而只会调用各自员工的虚拟输入函数)。输入和输出在概念上是对称的操作,暗示对称地实现它们,即在这种情况下都作为成员函数。
首先,如果你想使用多态性,你需要在你的向量中存储指针。由于 vector 是员工的唯一所有者,因此 std::vector<std::unique_ptr<Employee>>
之类的东西是合适的。
编辑:我看到您更新了矢量以使用指针。但是您正在存储指向本地堆栈分配对象的指针,例如 mEmp
。这是行不通的,当 mEmp
变量在右大括号处超出范围时,对象将被删除,您将在向量中留下一个指向已删除对象的悬空指针。使用此悬挂指针是未定义的行为。您需要使用 new
在堆上分配 Manager
。然后,当变量超出范围时,该对象将不会被删除,但您需要记住在完成后删除该对象。像 unique_ptr
这样的东西让这很容易。
关于您的问题:
- 尽量减少显式转换,尤其是向下转换。在将
Employee
存储在向量中时,它将从派生的 class 隐式向上转换为 Employee
但除此之外,不需要太多转换。
关于覆盖方法,您的想法大致正确,如果您在 Employee
指针上调用虚拟 printEmp
方法,它将调用派生的覆盖class。
如果您乐于让 Employee
classes 负责用户输入,您可以简单地添加一个虚拟方法,使用来自用户的适当输入来初始化员工。但我很想将其与您的域对象分开。无论如何,您都需要一个关于员工类型的用户选择的 switch 语句,因此多态性在那里不会给您带来太多好处。
如果你真的想为员工创建使用多态性,我建议使用类似抽象工厂模式的东西。
无论如何,这是我的建议:
#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();
}
我正在尝试创建一个员工数据库(员工向量)。有 3 种类型的员工,即。 employees 是基础 class,Manager、Engg 和 Scientist 是派生的 class。 每个员工都有名字和姓氏。除了名字之外,这 3 种类型的员工中的每一种都有独特的统计数据,即。经理有人数meetings/week 而工程师有工作经验等等。
我有几个问题 1. 我应该将派生对象向上转换为基数 class 还是将基数 class 向下转换为派生对象 class? 2. 我如何使用多态性来覆盖方法,因为我希望用户添加员工类型,并根据所选的类型显示相应的输入字段,即。如果是经理,除了名字和姓氏之外,程序还应该要求 meetings/week?
这是我的 Class 文件
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!
您可能希望在向量中存储指针以避免切片,正如其他人提到的那样。然后每个员工都可以有自己的输入法,并提出正确的问题来初始化自己(main 不会实现它,而只会调用各自员工的虚拟输入函数)。输入和输出在概念上是对称的操作,暗示对称地实现它们,即在这种情况下都作为成员函数。
首先,如果你想使用多态性,你需要在你的向量中存储指针。由于 vector 是员工的唯一所有者,因此 std::vector<std::unique_ptr<Employee>>
之类的东西是合适的。
编辑:我看到您更新了矢量以使用指针。但是您正在存储指向本地堆栈分配对象的指针,例如 mEmp
。这是行不通的,当 mEmp
变量在右大括号处超出范围时,对象将被删除,您将在向量中留下一个指向已删除对象的悬空指针。使用此悬挂指针是未定义的行为。您需要使用 new
在堆上分配 Manager
。然后,当变量超出范围时,该对象将不会被删除,但您需要记住在完成后删除该对象。像 unique_ptr
这样的东西让这很容易。
关于您的问题:
- 尽量减少显式转换,尤其是向下转换。在将
Employee
存储在向量中时,它将从派生的 class 隐式向上转换为Employee
但除此之外,不需要太多转换。 关于覆盖方法,您的想法大致正确,如果您在
Employee
指针上调用虚拟printEmp
方法,它将调用派生的覆盖class。如果您乐于让
Employee
classes 负责用户输入,您可以简单地添加一个虚拟方法,使用来自用户的适当输入来初始化员工。但我很想将其与您的域对象分开。无论如何,您都需要一个关于员工类型的用户选择的 switch 语句,因此多态性在那里不会给您带来太多好处。如果你真的想为员工创建使用多态性,我建议使用类似抽象工厂模式的东西。
无论如何,这是我的建议:
#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();
}