检查对象类型的哪种方法更好?

时间:2011-08-26 04:23:13

标签: c++

方法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);
            }
        }
    }
};

在问题中,有两种类型的EmployeePermanentEmployeeContractEmployee
有一个名为Manager的班级,其中包含在他下工作的所有员工的清单 对于ContractEmployee,它必须调用函数setWorkingDuration(),该函数在类assignWorkingHour的方法Manager中调用。

问题是:
此处Employee的{​​{1}}类型由dynamic_cast运算符确定,Manager必须知道Employee的所有类型的派生类。

方法2

在班级Employee中添加其他成员:

enum TypeOfEmployee {CONTRACT, PERMANENT};

并检查TypeOfEmployee以确定Employee

的类型

请告诉我哪个更好或者有其他方法吗?

5 个答案:

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