1

Tengo un error de compilación undefined reference to en un método heredado en C++. He leído una conversación en un foro de openclassrooms y respuestas en StackOverflow, pero ninguna me ayudaba.

El primero me dice que es un error de principiante con una mezcla de C y C++ o un enlazado que no está bien establecido. No sé lo que es un enlazador y leí en Wikipedia que:

un enlazador (linker) es un programa que toma los objetos generados en los primeros pasos del proceso de compilación, la información de todos los recursos necesarios (biblioteca), quita aquellos recursos que no necesita, y enlaza el código objeto con su(s) biblioteca(s) con lo que finalmente produce un fichero ejecutable o una biblioteca.

Aquí está el error:

$ g++ main.cpp MaxSize.cpp -o main
/tmp/ccG0cfMh.o: In function `MaxSize::MaxSize(int)':
MaxSize.cpp:(.text+0x34): undefined reference to `TasMin::TasMin(int)'
MaxSize.cpp:(.text+0x151): undefined reference to `TasMin::~TasMin()'
/tmp/ccG0cfMh.o: In function `MaxSize::~MaxSize()':
MaxSize.cpp:(.text+0x1b1): undefined reference to `TasMin::~TasMin()'
/tmp/ccG0cfMh.o:(.rodata._ZTV7MaxSize[_ZTV7MaxSize]+0x20): undefined reference to `TasMin::min_heapify(int)'
/tmp/ccG0cfMh.o:(.rodata._ZTI7MaxSize[_ZTI7MaxSize]+0x10): undefined reference to `typeinfo for TasMin'
collect2: error: ld returned 1 exit status

Aquí está la parte MaxSize.cpp que pienso que nos interesa:

#include "MaxSize.h"

#include<iostream>

using namespace std;

MaxSize::MaxSize(int size):TasMin(size){
    int array[size];
    for (int i = 0; i < size; i++)
        {
            cout<<"enter element"<<(i)<<endl;
            cin>>array[i];
        }
    build_minheap(array, size);
}


MaxSize::~MaxSize()
{
    delete[] array;
}


// funcion que construye un árbol
void MaxSize::build_minheap(int *array, int n)
{   
    int entier;

    for(int i=size/2;i>=0;i--)
    {

        min_heapify(array,i,n);

    }

}


// funcion que situa los elementos colocado al azar del array en el array    
void MaxSize::min_heapify(int* array, int i, int size)
{

    int j, temp;

    temp = array[i];
    j=2*i;
    while(j<=size)
    {
        if(j<size && array[j+1] <array[j])
            j= j+1;
        if(temp<array[j])
            break;
        else if (temp >=array[j])
        {
            array[j/2]=array[j];
            j=2*j;
        }
    }

    array[j/2]=temp;

}

Aquí está el prototipo MaxSize.h:

#include "TasMin.h"

class MaxSize : public TasMin
{
  public:
    MaxSize(int size);

    MaxSize(int* array, int length);
    ~MaxSize();

    virtual void min_heapify(int* array, int i, int size);
    virtual void build_minheap(int* array,int size);


    private:
    int size;
    int* array;

};

Y, finalmente, aquí está TasMin.h:

class TasMin
{
  public:
    TasMin(int size);
    virtual ~TasMin();

    virtual void min_heapify(int size);
    virtual void build_minheap(int* array,int size);

    private:
    int size;

};

main.cpp

#include <iostream>
#include "MaxSize.h"

using namespace std;

int main(){

    int size,i,x;
    cout<<"enter no of elements of array\n"<<endl;
    cin>>size;
    MaxSize* tableau = new MaxSize(size); // va falloir modifier MaxSize.h et .cpp
}

¿Me pueden ayudar a librarme de este error?

Revolucion for Monica
  • 4,154
  • 4
  • 28
  • 80
  • ¿Podrías proporcionarnos un [ejemplo mínimo, completo y verificable](https://es.stackoverflow.com/help/mcve)? Por ejemplo, para reproducir tu problema necesitamos un `MainTasMin.cpp` básico. Por lo pronto voy a ir echando un vistazo al código. – OscarGarcia Apr 26 '17 at 06:32
  • Gracias por la edición. Pude reproducir tu problema haciendo una implementación vacía de `build_minheap` y `min_heapify`. También improvisé un `main()` para completar el proceso de compilación completo. ¿Podrías revisar mi respuesta? – OscarGarcia Apr 26 '17 at 07:01
  • @OscarGarcia Gracias por su respuesta. Entonces voy a vaciar `build_minheap` y `min_heapify` en `MaxSize.cpp` y comentar por un lado y revisar su respuesta! No tengo de `main.cpp` pero un `MainTasMin.cpp` – Revolucion for Monica Apr 26 '17 at 07:05
  • @Trauma basta con sustituir MainTasMin.cpp por Main.cpp y listo. @Marine1, no es necesario variar `build_minheap` y `min_heapify`, esa fue la solución que adopté para reproducir el problema, pero con mi respuesta lo solucioné. Échale un vistazo, he probado con el código completo que has publicado y me compila todo correctamente. – OscarGarcia Apr 26 '17 at 07:09
  • 1
    Por lo que puedo ver no es hispanoparlante. Yo he participado en la versión inglesa de stackoverflow y sé que mis respuestas no están lexicológicamente bien formadas, pero me hago entender. Creo que él se esfuerza en hacerse entender y, aunque faltaba código para reproducir "cómodamente" su problema, no era difícil hacerlo. Olvidó la definición de las funciones, es un error fácil de detectar y corregir. – OscarGarcia Apr 26 '17 at 07:20
  • ¡ Ahora sí ! Ahora se entiende correctamente todo. – Trauma Apr 26 '17 at 07:28
  • @Trauma ¡Jaja! ;) – Revolucion for Monica Apr 26 '17 at 07:29
  • Ahora, con más tiempo, he redactado una respuesta más completa sugiriendo soluciones con definiciones virtuales puras y eliminando la definición explícita vacía del constructor y destructor del padre. – OscarGarcia Apr 26 '17 at 08:01
  • Puede que [esta guía](https://es.stackoverflow.com/questions/65557/simbolo-externo-sin-resolver-qu%c3%a9-he-hecho-mal) te ayude a entender el problema. – PaperBirdMaster Apr 26 '17 at 10:17

1 Answers1

4

Parece que el error es que has definido la clase TasMin sin implementación de sus métodos (como sí has hecho, por el contrario, con las implementaciones de los métodos del constructor y destructor en MaxSize).

Una solución rápida sería una implementación vacía en TasMin.h:

class TasMin
{
  public:
    TasMin(int size) {}
    virtual ~TasMin() {}

    virtual void min_heapify(int size) {}
    virtual void build_minheap(int* array, int size) {}

    private:
    int size;
};

Sin embargo esto soluciona los síntomas pero no arregla el diseño de las clases.

Si quieres definir las funciones como virtuales puras (con la marca = 0) estás obligando a las hijas a implementar esas funciones, pero en tu código estás implementando otras diferentes (recuerda que se consideran diferentes las funciones con número o tipo de parámetros también diferentes):

/* Clase padre */
void TasMin::min_heapify(int size);
/* Clase hija */
void MaxSize::min_heapify(int* array, int i, int size);

Entonces, otra forma de solucionar el problema sería con el siguiente TasMin.h:

class TasMin
{
  public:
    TasMin(int size) {}
    ~TasMin() {}

    virtual void min_heapify(int* array, int i, int size) = 0;
    virtual void build_minheap(int* array,int size) = 0;

    private:
    int size;
};

En el que sigo haciendo una implementación vacía del constructor y destructor.

Si no quieres hacer definiciones vacías entonces puedes tener un TasMin.h así:

class TasMin
{
  public:
    virtual void min_heapify(int* array, int i, int size) = 0;
    virtual void build_minheap(int* array,int size) = 0;

    private:
    int size;
};

Pero, para que no requiera del constructor en la clase padre, la hija debe definir su constructor así en MaxSize.cpp:

MaxSize::MaxSize(int size) {
    int array[size];
    for (int i = 0; i < size; i++)
        {
            cout<<"enter element"<<(i)<<endl;
            cin>>array[i];
        }
    build_minheap(array, size);
}

Espero que te sea de ayuda.

OscarGarcia
  • 26,999
  • 3
  • 26
  • 61
  • ¡ Muchas gracias ! (PS :Pienso que falta punto y comas en su respuesta) – Revolucion for Monica Apr 26 '17 at 07:32
  • Los bloques no requieren de puntos y comas al final de ellos pero, por ejemplo, [la definición de la clase sí](http://en.cppreference.com/w/cpp/language/class) (o de una estructura, unión, etc). Por ese motivo es necesario el punto y coma al final de la definición de clase y no tras la implementación de las funciones. – OscarGarcia Apr 26 '17 at 07:42
  • 1
    Buena respuesta. No te puedo dar +2 jeje – Trauma Apr 26 '17 at 08:04