方法1 :
class Employee
{
public:
virtual int calculateSalary() = 0;
};
class PermanentEmployee : public Employee {
const int salaryPerMonth;
public:
PermanentEmployee(int sal) : salaryPerMonth(sal){}
int calculateSalary() {
return salaryPerMonth;
}
};
class ContractEmployee : public Employee {
const int wagesPerHr;
int totalHour;
public:
ContractEmployee(int sal) : wagesPerHr(sal), totalHour(0){}
void setWorkingDuration(int time) {
totalHour = totalHour + time;
}
int calculateSalary() {
return wagesPerHr * totalHour;
}
};
class Manager {
list<Employee *> ls;
public:
void assignWorkingHour() {
list<Employee *>::iterator it;
for(it = ls.begin(); it != ls.end(); it++) {
Employee *emp = *it;
ContractEmployee* contractEmp = dynamic_cast<ContractEmployee* >(emp);
if(contractEmp) {
contractEmp->setWorkingDuration(5);
}
}
}
};
在问题中,有两种类型的Employee
:PermanentEmployee
和ContractEmployee
。
有一个名为Manager
的班级,其中包含在他下工作的所有员工的清单
对于ContractEmployee
,它必须调用函数setWorkingDuration()
,该函数在类assignWorkingHour
的方法Manager
中调用。
问题是:
此处Employee
的{{1}}类型由dynamic_cast
运算符确定,Manager
必须知道Employee
的所有类型的派生类。
方法2 :
在班级Employee
中添加其他成员:
enum TypeOfEmployee {CONTRACT, PERMANENT};
并检查TypeOfEmployee
以确定Employee
请告诉我哪个更好或者有其他方法吗?
答案 0 :(得分:7)
更好的方法是编写不需要确切对象类型知识的代码。在我看来,解决这个问题最优雅的方法是将setWorkingDuration()
移到员工类。可能是这样的:
class Employee
{
public:
// Calculates the salary for this employee.
// Returns the calculated salary.
virtual int calculateSalary() = 0;
// Sets the working duration. Does nothing if the employee is permanent.
// Returns true if Employee is on a contract, false if permanent.
virtual bool setWorkingDuration(int time)
{
return false;
}
};
class PermanentEmployee : public Employee
{
const int salaryPerMonth;
public:
PermanentEmployee(int sal) : salaryPerMonth(sal) {}
int calculateSalary()
{
return salaryPerMonth;
}
};
class ContractEmployee : public Employee
{
const int wagesPerHr;
int totalHour;
public:
ContractEmployee(int sal) : wagesPerHr(sal), totalHour(0) {}
int calculateSalary()
{
return wagesPerHr * totalHour;
}
bool setWorkingDuration(int time)
{
totalHour = totalHour + time;
return true;
}
};
class Manager
{
list<Employee *> ls;
public:
void assignWorkingHours()
{
list<Employee *>::iterator it;
for(it = ls.begin(); it != ls.end(); it++)
{
Employee* emp = *it;
emp->setWorkingDuration(5);
}
}
};
这样,Manager
课程不必知道Employee
实际上是PermanentEmployee
还是ContractEmployee
。这就是多态性给你的东西。一般来说,如果你必须使用dynamic_cast<>
,你可能想再看一下设计,看看你是否可以省略它。
答案 1 :(得分:2)
嗯,子类型多态的全部意义是允许具体的子类定义自己的行为。你正在做的是匹配你拥有的对象类型,然后指定依赖于它的行为。从本质上讲,你已经复制了整个子类型,因此错过了它。 :)
我的建议?将此行为作为virtual
上的Employee
方法委托给对象本身(而不是其经理)。
答案 2 :(得分:0)
当然你可以使用dynamic_cast运算符和枚举TypeOfEmployee,但最后一个与多态性没什么共同之处。
您应该考虑为什么Manager将工作时间设置为PermanentEmployee。好吗? 另一种方法是使用setWorkingDuration虚方法扩展基类接口Employee。然后在PermanentEmployee中它什么都不做。
答案 3 :(得分:0)
其他人已经为典型案例提供了答案(值得接受)。
以下是不太典型案例的一些注释:
如果可以避免在运行时使用动态类型,则可以减少二进制大小(导出符号数),执行时间,动态分配计数,总内存使用量和运行时错误的几率。
删除虚拟和运行时多态可以将大小减少75%以上。
同样,您可以使用变量来识别简单情况下的类型或实现(例如,您的方法2)。
我做了一个简单的测试。它使用了多种动态类型(360,特别是),rtti等。生成了588K大小的dylib。有效地用函数指针替换虚方法和运行时多态性将其降低到130K。那还是360班。
使用变量将实现合并到单个类只会将dylib的大小降低到10K。
再次,这种方法对二进制大小的影响要大得多。
我的观点是,在适当的情况下,这是一个很好的替代。
答案 4 :(得分:0)
方法三:分别跟踪承包商。
class Manager {
typedef list<Employee*> Employees; // Contains all employees, including contractors.
typedef list<ContractEmployee*> Contractors; // Contractors are in this list as well.
Employees employees;
Contractors contractors;
public:
void assignWorkingHour() {
for(Contractors::iterator it = contractors.begin(); it != contractors.end(); ++it) {
(*it)->setWorkingDuration(5);
}
}
int calculateEmployeeCost() {
int totalSalary = 0;
for (Employees::const_iterator it = employees.begin(); it != employees.end(); ++it) {
totalSalary += (*it)->calculateSalary();
}
return totalSalary;
}
};