2011-08-26 11 views
6

Enfoque: 1que es el mejor enfoque para comprobar el tipo de objeto

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

En el problema, hay 2 tipo de empleado: PermanentEmployee y ContractEmployee. Hay una clase llamada Manager que contiene una lista de todos los empleados que trabajan con él. Para ContractEmployee, tiene que invocar la función setWorkingDuration, que se invoca en el método assignWorkingHour of class Manager.

El problema es: Aquí tipo de empleado es ser determind por el operador dynamic_cast y director tiene que saber acerca de todo tipo de clase derivan del Empleado

Approach2: añadir otro miembro en la clase Empleado

 enum TypeOfEmployee {CONTRACT, PERMANENT}; 

y comprobar TypeOfEmployee para determinar el tipo de empleado

Informe a que es mejor o ¿hay algún enfoque alternativo?

+0

Me gusta la pregunta. Me preocupé por el costo de dynamic_cast. – Lou

+0

http://www.nerdblog.com/2006/12/how-slow-is-dynamiccast.html puede ser una lectura relevante para usted. –

+0

¿Es esta una pregunta para la tarea? Tengo curiosidad. –

Respuesta

7

El mejor enfoque es escribir código que no requiere conocimiento sobre el tipo de objeto exacto. Me parece que la forma más elegante de lidiar con esto es mover el setWorkingDuration() a la clase de empleado. Probablemente así:

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

De esta manera, la clase Manager no tiene que saber si el Employee es en realidad un PermanentEmployee o una ContractEmployee. Eso es lo que le da el polimorfismo. En términos generales, si tiene que usar dynamic_cast<>, es posible que desee echar un vistazo al diseño y ver si puede omitirlo.

+0

¡Pégame! Bien dicho. –

+0

Con respecto al uso de muestra proporcionado, no hay necesidad de devolver un valor. Las clases derivadas simplemente incrementan sus horas trabajadas o no hacen nada. En ese caso, setWorkingDuration() no necesita ser puramente virtual, y solo se puede implementar en clases que se preocupen por las horas trabajadas (dejando a la clase base con una implementación vacía). –

+0

@Jack Smith: Correcto. Es por eso que dije "Probablemente así". :-) Si la información acerca de si la función 'setWorkingDuration()' hace algo realmente no es interesante o no es necesaria, entonces la función simplemente puede devolver 'void'. –

2

Bueno, el objetivo del polimorfismo de subtipo es permitir que las subclases concretas definan su propio comportamiento. Lo que estás haciendo es hacer coincidir el tipo de objeto que tienes, y luego especificar el comportamiento que depende de eso. Esencialmente, ha duplicado el punto completo de los subtipos y, por lo tanto, lo ha omitido. :)

¿Mi sugerencia? Delegue este comportamiento al objeto mismo (no a su administrador) como un método virtual en Employee.

0

Por supuesto, puedes hacer dynamic_cast al igual que enum TypeOfEmployee, pero el último no tiene nada en común con el polimorfismo.

Debería pensar por qué Manager establece horas de trabajo para PermanentEmployee. ¿Está bien? Otro enfoque es expandir la interfaz de la clase base Empleado con el método virtual setWorkingDuration. Entonces en PermanentEmployee no hará nada.

0

Los otros ya han proporcionado la respuesta (vale la pena aceptar) para casos típicos.

Estas son algunas notas para los casos menos típicos:

puede reducir su tamaño binario (número de símbolos exportados), los tiempos de ejecución, el recuento de las asignaciones dinámicas, uso total de memoria, y la posibilidad de errores de tiempo de ejecución si se puede evite usar tipos dinámicos en tiempo de ejecución.

eliminando los virus virtuales y el polimorfismo en tiempo de ejecución puede reducir el tamaño en más del 75%.

Del mismo modo, se pueden utilizar variables para identificar tipos o implementaciones en casos sencillos (por ejemplo, el enfoque 2).

hice una prueba sencilla. que utiliza múltiples tipos dinámicos (360, específicamente), rtti, etc. Se generó una dylib de la 588K tamaño.

que sustituye eficazmente métodos virtuales y polimorfismo de tiempo de ejecución con punteros de función trae abajo a 130K. eso sigue siendo 360 clases.

la consolidación de la aplicación a una única clase con variables sólo trajo el tamaño de la dylib hasta 10K.

de nuevo, este enfoque afecta mucho más que el tamaño binario.

mi punto es que este es un buen cambio en las circunstancias adecuadas.

0

enfoque de tres: realizar un seguimiento de los contratistas por separado.

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