2011-01-04 34 views
6

gsoap con sus herramientas y wsdl2h soapcpp2 me proporcionaron un archivo soapStub.h que contiene lo siguiente:referencia indefinida a VTABLE - miembro virtual, generada por las clases gsoap

class SOAP_CMAC ns2__SOAPKunden 
{ 
    public: 
    std::string *adresszusatz; 
    // ... 
    public: 
    virtual int soap_type() const { return 7; } 
    // ... 
    ns2__SOAPKunden() : adresszusatz(NULL), x(NULL) { } // left out all member init. 
    virtual ~ns2__SOAPKunden() { } 
}; 

comienzo con una pequeña aplicación utilizando la clase para poblar objetos con datos de la base de datos informix.

Pero para compilar correctamente tengo que dejar fuera todas las cosas virtuales - me encontré con muchas publicaciones acerca de este error y el uso de los miembros virtuales en las subclases - de lo contrario me sale

main.o: In function `ns2__SOAPKunden::ns2__SOAPKunden()': 
main.cpp:(.text._ZN15ns2__SOAPKundenC1Ev[ns2__SOAPKunden::ns2__SOAPKunden()]+0xf): undefined reference to `vtable for ns2__SOAPKunden' 
main.o: In function `ns2__SOAPKunden::~ns2__SOAPKunden()': 
main.cpp:(.text._ZN15ns2__SOAPKundenD1Ev[ns2__SOAPKunden::~ns2__SOAPKunden()]+0x13): undefined reference to `vtable for ns2__SOAPKunden' 
collect2: ld returned 1 exit status 

Admito después de años de secuencias de comandos sólo se es muy difícil para mí dar sentido al código C++ ... Quiero pedir consejo sobre qué probar a continuación. Mi clase no es una clase derivada, es por ejemplo lo que me hace pensar.

+0

Si no está utilizando clases derivadas, ¿por qué la función es virtual? –

Respuesta

14

El error significa que la tabla virtual no se ha compilado correctamente/vinculado en el binario final (ejecutable o biblioteca). Hay dos circunstancias comunes que conducen a este error:

  • no está vinculando el archivo objeto que incluye las definiciones de la tabla virtual --i.e. se ha compilado en soapStub.cppsoapStub.o, pero no agregó que binaria a la línea de comandos del vinculador.
  • el compilador no está generando la tabla virtual en cualquier lugar, por lo que incluso si está incluyendo todos los archivos objeto, que no incluye la tabla virtual.

El segundo caso es el más difícil de identificar para desarrolladores no experimentados, y puede ser causado por una clase que se define en el encabezado y contiene funciones virtuales. Si se definen todas las funciones virtuales inline, el compilador generará la mesa virtual en todas las unidades de traducción que incluyen la cabecera, y se marca como un símbolo débil para que el enlazador puede desprenderse de ellos, pero si más tarde añadir un nuevo método virtual y lo deja sin definir en la cabecera -o si se quita la definición de uno de los functions-- virtual, entonces el compilador no generará la tabla virtual en cada unidad de traducción, pero sólo en la que define esas funciones.

Lo que debe verificar:

  • está vinculando todos los ficheros objeto
  • o bien todas las funciones virtuales se definen en línea en la definición de clase o si tiene un .cpp que define las funciones virtuales y que está vinculando . en
+2

El problema puede ser que uno ha declarado el destructor en la clase derivada de uno, pero no lo ha definido. ¿Esa situación está cubierta aquí? – Moberg

+0

@Moberg: Sí, el segundo caso. Algunos compiladores (gcc entre ellos) generarán el vtable en una sola unidad de traducción. GCC definirá el vtable solo en la unidad de traducción que contenga la función virtual no en línea * first * (en orden de declaración), que en muchos casos será el destructor (a menudo las definiciones de clase comienzan con constructores/destructores) –

+1

Clang tiene un ' -Wweak-vtable' advertencia para esto (me enteré por casualidad al intentar '-Weverything' en una biblioteca de solo cabecera) – TemplateRex

0

esto es lo que David Rodríguez dijo, se acaba de decir más simple supongo ...

tuve esta situación en mi clase de interfaz:

class IBase 
{ 
    public: 
    virtual void begin(unsigned long); 
    virtual void end(); 
    virtual int available(void) = 0; 
    virtual int peek(void) = 0; 
    virtual int read(void) = 0; 
    virtual void flush(void) = 0; 
} 

y cambiado a esto:

class IBase 
{ 
    public: 
    virtual void begin(unsigned long) = 0; 
    virtual void end() = 0; 
    virtual int available(void) = 0; 
    virtual int peek(void) = 0; 
    virtual int read(void) = 0; 
    virtual void flush(void) = 0; 
} 

la que hizo el truco.

begin() y al final() se definieron en la clase derivada en un archivo diferente, clase IBase (interfaz), sólo se declaró en la cabecera y se incluye en pocos lugares.

El error de OP solo apareció cuando establecí optimizaciones en ninguno (-O0), cualquier otra configuración no produjo ningún error (gcc 4.8).

Cuestiones relacionadas