2011-12-27 9 views
7

¿Es esencial tener una definición para una función virtual?¿Debería una función virtual esencialmente tener una definición?

Considere este programa muestra a continuación:

#include <iostream> 

using namespace std; 

class base 
{ 
    public: 
     void virtual virtualfunc(); 
}; 

class derived : public base 
{ 
    public: 
    void virtualfunc() 
    { 
     cout << "vf in derived class\n"; 
    } 
}; 

int main() 
{ 
    derived d; 
    return 0; 
} 

Esto le da al enlace de error:

In function base::base() :: undefined reference to vtable for base

que no tienen la definición para la función virtual en la clase base. ¿Por qué ocurre este error aunque no haya invocado explícitamente la función virtual?

Lo interesante que encuentro es que si no instalo un objeto de la clase derived, el error de enlace ya no existe. ¿Por qué es esto? ¿Qué tiene que ver la creación de instancias con el error de enlace anterior?

+1

Vuelva a su edición: si no instancia un 'derivado' o una' base', ¿por qué el enlazador tiene que hacer algo con cualquier método de esas dos clases? Si no se hace referencia a las clases, el vinculador no tiene ninguna razón para intentar buscarlas en los archivos del objeto. (A menos que esté construyendo una biblioteca.) – Mat

+0

@Mat: Estoy de acuerdo :) –

Respuesta

10

El C++ estándar ISO especifica que se deben definir todos los métodos virtuales de una clase que no son puras-virtual.

Referencia:

C++ 03 estándar: 10,3 funciones virtuales [class.virtual]

A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required (3.2).

Así que, o deben hacer la función virtual pura o proporcionar una definición para él.

Si está utilizando gcc, es posible que obtenga algunos errores extraños si no cumple con esta especificación estándar. Los gcc faq documentacion TI, así:

The ISO C++ Standard specifies that all virtual methods of a class that are not pure-virtual must be defined, but does not require any diagnostic for violations of this rule [class.virtual]/8 . Based on this assumption, GCC will only emit the implicitly defined constructors, the assignment operator, the destructor and the virtual table of a class in the translation unit that defines its first such non-inline method.

Therefore, if you fail to define this particular method, the linker may complain about the lack of definitions for apparently unrelated symbols. Unfortunately, in order to improve this error message, it might be necessary to change the linker, and this can't always be done.

The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7 .

+0

¡Genial !. Excelente :) –

3

Debe proporcionar una definición o marcarla como abstract/pure-vitual.

void virtual virtualfunc() = 0; 
+0

Conciso y más o menos lo dice todo. – Gravity

8

es necesario proporcionar una implementación de una función virtual (con su comportamiento por defecto) a menos que se defina la función de ser "virtual pura".

Así que su ejemplo podría ser:

class base 
{ 
    public: 
     void virtual virtualfunc() {} //intentionally do nothing; 
}; 

o

class base 
{ 
    public: 
     void virtual virtualfunc()=0; //pure virtual; 
}; 
0

Sí que se necesita un cuerpo, pero tal vez lo que se está refiriendo a que se llama un funciones virtuales puras, que no necesitaría una definición en la clase base.

La sintaxis para definir aquellos es el siguiente:

void virtual virtualfunc() = 0; 
1

En respuesta al error sobre la viable: el comando virtual en este caso dice C++ para producir una tabla virtual de los métodos de la clase base. De esta forma, cuando usa polimorfismo, C++ puede reemplazar los métodos virtuales de la clase base con los métodos de la clase derivada con el mismo nombre durante el tiempo de ejecución. Este error le dice al usuario que este reemplazo no es posible. Para corregir este error, deberá implementar el método o establecerlo como puramente virtual agregando "= 0" al final de la definición.

En respuesta a las ediciones: La razón por la que no se obtiene un error al instanciar el objeto como una clase base es porque la clase base no necesita acceder a la tabla virtual. Por otro lado, si realmente intentas utilizar este método, deberías obtener un error ya que no existe implementación. En otras palabras, aunque pueda instanciar un objeto de la clase base, no es una clase completa.

+1

¡Esta es la razón! – selfboot

Cuestiones relacionadas