C++ 检查对象类型的更好方法是什么?

C++ 检查对象类型的更好方法是什么?,c++,C++,方法1: class Employee { public: virtual int calculateSalary() = 0; }; class PermanentEmployee : public Employee { const int salaryPerMonth; public: PermanentEmployee(int sal) : salaryPerMonth(sal){} int calculateSalary() { r

方法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);
            }
        }
    }
};
并检查
TypeOfEmployee
以确定
Employee的类型


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

更好的方法是编写不需要了解确切对象类型的代码。在我看来,处理这个问题最优雅的方法是将
setWorkingDuration()
移动到employee类。可能是这样的:

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);
        }
    }
};
class员工
{
公众:
//计算此员工的工资。
//返回计算的薪资。
虚拟整数calculateSalary()=0;
//设置工作持续时间。如果员工是永久员工,则不执行任何操作。
//如果员工签订了合同,则返回true;如果是永久员工,则返回false。
虚拟布尔设置工作持续时间(整数时间)
{
返回false;
}
};
类别永久雇员:公共雇员
{
工薪月常数;
公众:
永久雇员(int sal):工资月(sal){}
int calculateSalary()
{
每月返回工资;
}
};
类别ContractEmployee:公共雇员
{
瓦格斯佩尔常数;
整小时;
公众:
合同雇员(内部sal):工资总额(sal),总小时数(0){}
int calculateSalary()
{
返回下注率*总小时;
}
布尔设置工作持续时间(整数时间)
{
总小时=总小时+时间;
返回true;
}
};
班级经理
{
列表ls;
公众:
无效分配工作时间()
{
列表::迭代器;
for(it=ls.begin();it!=ls.end();it++)
{
员工*emp=*it;
emp->设置工作持续时间(5);
}
}
};

这样,
经理
类就不必知道
员工
实际上是
永久员工
还是
合同员工
。这就是多态性给你的。一般来说,如果您必须使用
dynamic\u cast
,您可能需要再看一看设计,看看是否可以省略它。

好的,子类型多态性的全部要点是允许具体的子类定义自己的行为。您所做的是根据您拥有的对象类型进行匹配,然后根据该类型指定行为。本质上,您复制了整个子类型点,因此错过了它。:)


我的建议?将此行为作为
Employee

上的
virtual
方法委托给对象本身(而不是其管理者),当然您可以使用dynamic_cast操作符以及enum TypeOfEmployee,但最后一个与多态性没有任何共同之处

你们应该想想为什么经理会把工作时间定为永久雇员。可以吗?
另一种方法是使用setWorkingDuration虚拟方法扩展基类接口Employee。那么对于永久雇员来说,它将一事无成。

其他人已经为典型案例提供了答案(值得接受)

以下是一些不太典型的情况的注意事项:

如果可以避免在运行时使用动态类型,则可以减少二进制大小(导出符号的数量)、执行时间、动态分配计数、总内存使用量以及出现运行时错误的几率

删除虚拟和运行时多态性可以将大小减少75%以上

类似地,您可以在简单的情况下(例如,您的方法2)使用变量来标识类型或实现

我做了一个简单的测试。它使用了多种动态类型(特别是360)、rtti等。生成了大小为588K的动态库

有效地用函数指针替换虚拟方法和运行时多态性,使其降低到130K。那仍然是360节课

将实现合并到一个带有变量的类只会使动态库的大小降低到10K

同样,这种方法影响的不仅仅是二进制大小


我的观点是,在适当的情况下,这是一个很好的替代方法。

方法三:单独跟踪承包商

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;
    }
};
类管理器{
typedef列出员工;//包含所有员工,包括承包商。
typedef列出承包商;//承包商也在此列表中。
员工;
承包商;
公众:
无效分配工时(){
对于(Contractors::iterator it=Contractors.begin();it!=Contractors.end();++it){
(*it)->设置工作持续时间(5);
}
}
int calculateEmployeeCost(){
int totalSalary=0;
for(Employees::const_iterator it=Employees.begin();it!=Employees.end();++it){
工资总额+=(*it)->计算工资();
}
返回总工资;
}
};

喜欢这个问题。我对动态演员的成本感到好奇。可能是你的相关读物。这是家庭作业问题吗?我只是好奇。不,这不是家庭作业问题。实际上,我在设计一个项目时遇到过这种类型的问题。关于提供的示例用法,不需要返回值。派生类要么增加工作时间,要么什么都不做。在这种情况下,setWorkingDuration()不需要是纯虚拟的,并且只能在关心工作小时数的类中实现(将基类保留为空实现)。@Jack Smith:正确。这就是为什么我说“可能是这样的。”:-)如果关于
setWorkingDuration()
函数是否做任何事情的信息实际上不有趣或不需要,那么该函数只需返回
void
。非常感谢您宝贵的输入
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;
    }
};