2010-07-21 6 views
7

Estaba leyendo Google C++ Style Guide, y me confundí en la parte Doing Work in Constructors. Una de las desventajas de hacer el trabajo pesado en el constructor es:Duda en una desventaja de hacer el trabajo en los constructores

Si el trabajo llama a funciones virtuales, estas llamadas no consiguen enviados a las implementaciones de las subclases. futura modificación a su clase puede introducir en silencio este problema incluso si la clase no está actualmente subclase, causando mucha confusión.

No entendí lo que significa. ¿Podría alguien dar una explicación y por qué esto puede considerarse una desventaja?

+2

Esta es una de las razones por las que no me gusta la guía de estilo de google C++. Llamar a los métodos virtuales desde constructores y destructores debe evitarse per se como regla general, donde evitarlo solo lo hace si tiene un buen motivo y puede defenderlo en una revisión del código. Por otro lado, la recomendación de usar una inicialización de dos pasos es (indiscutiblemente) errónea, y muchas otras guías de estilo recomiendan contra la inicialización en dos pasos ... –

+2

Tenga en cuenta que la guía de estilo de Google no es C++, a pesar del título de la página . Prohíben las excepciones, dando un lenguaje bastardo en el que muchas expresiones idiomáticas de C++ no se pueden usar o se les quita su utilidad. Esta es la razón por la que requieren una inicialización en dos etapas y todos los dolores de cabeza propensos a errores que esto conlleva; no hay forma de indicar falla de un constructor. A menos que tenga una razón específica para seguir el estilo de Google, ignórelo. –

Respuesta

9

estoy descaradamente arrancando un código de ejemplo de la página de Wikipedia Virtual function:

#include <iostream> 
#include <vector> 

class Animal { 
    public: 
     virtual void eat() const { 
      std::cout << "I eat like a generic Animal." << std::endl; 
     } 
     virtual ~Animal() { 
     } 
}; 

class Wolf : public Animal { 
    public: 
     void eat() const { 
      std::cout << "I eat like a wolf!" << std::endl; 
     } 
}; 

class Fish : public Animal { 
    public: 
     void eat() const { 
      std::cout << "I eat like a fish!" << std::endl; 
     } 
}; 

Si llama eat() dentro del Animal constructor, se llamará a la Animaleat() funcionan todo el tiempo. Incluso cuando se crea un objeto o una WolfFish, ya que el constructor Animal completará antes de que se inicializa el objeto de subclase, no existirán los primordiales eat funciones todavía.

Esto es una desventaja porque puede causar confusión entre lo que se espera y lo que realmente sucede. Si sobreescribo eat y luego creo un objeto de mi subclase, espero que se llame a mi función reemplazada, incluso desde una referencia Animal. Lo espero porque eso es lo que sucede cuando la llamada se hace explícitamente por código fuera del constructor. El comportamiento es diferente dentro del constructor, haciendo que me rasque la cabeza con desconcierto.

+8

No 'clase Lizard'? –

+2

@Justin: No puedo * creer * Perdí esa oportunidad. ;) –

4

Cuando se construye un objeto, los constructores para las clases base se llaman primero. Dado que la clase derivada aún no se ha inicializado, cualquier llamada a métodos virtuales durante el constructor de la clase base no tendrá un objeto de clase derivado para trabajar.

0

El trabajo del constructor es simplemente inicializar el estado inicial de su objeto. Si comienza a realizar tareas que se basan en acciones realizadas en funciones virtuales, puede obtener algunos resultados inesperados cuando las subclases comiencen a implementar estas funciones.

1

Si se hereda de la clase, los métodos que se anulan/poner en práctica no será anunciado en este caso. Entonces, si el empleado llama a work() en el constructor, luego se le ocurre que Hourly :: work() y SalariedEmployee :: work() no se llamarán. A pesar de que tienen implementaciones diferentes, todavía se tratarán como Empleados, no como sus implementaciones especiales.

2

Cuando se crea una instancia de una subclase, primero se llama el constructor de la clase base, entonces el constructor de la subclase.

Si el constructor de la clase base llama un método virtual, entonces el método de la clase base será llamado en lugar de la subclase, aunque el ejemplo es el de una subclase. Esto podría ser un problema.

mucha más información aquí: http://www.artima.com/cppsource/nevercall.html

0

El comportamiento que las llamadas a funciones virtuales no son virtuales está bien definida, pero muy sorprendente, por lo general, los compiladores emiten advertencias.

Cuestiones relacionadas