2009-03-07 28 views
12

Antecedenteserror LNK2005: ya definido - C++

Tengo un proyecto llamado PersonLibrary que tiene dos archivos.

  1. Person.h
  2. Person.cpp

Esta biblioteca produce un archivo de biblioteca estática. Otro proyecto es TestProject que utiliza PersonLibrary (Agregado a través de dependencias de proyecto en VS008). Todo funcionó bien hasta que agregué una función no miembro a Person.h. Person.h parece

class Person 
{ 
public: 
    void SetName(const std::string name); 

private: 
    std::string personName_; 
}; 

void SetPersonName(Person& person,const std::string name) 
{ 
    person.SetName(name); 
} 

Person.cpp define SetName función. Cuando intento utilizar SetPersonName desde TestProject, obtengo el error LNK2005: ya se ha definido. Aquí es como lo he usado

#include "../PersonLibrary/Person.h" 
int main(int argc, char* argv[]) 
{ 
    Person person; 
    SetPersonName(person, "Bill"); 
    return 0; 
} 

Soluciones provisionales trató

1 - He quitado la Person.cpp y define toda la clase en Person.h. El error desapareció y todo funcionó.

2 - Cambiado el SetPersonName modificador a estática. Al igual que el siguiente

static void SetPersonName(Person& person,const std::string name) 
{ 
    person.SetName(name); 
} 

Preguntas

  1. Por qué el código mostrado por primera vez que no funciona como esperaba?
  2. ¿Qué diferencia hay estática hecha aquí?
  3. ¿Cuál es la solución adecuada para este problema?

Gracias

Respuesta

22

Usted tiene que

  • movimiento SetPersonName 's definición a un archivo .cpp, compilar y enlazar con el objetivo resultante
  • hacen SetPersonName línea

Ésta es una caso bien conocido de violación de una regla de definición.

La palabra clave static hace que el enlace de la función sea interno, es decir, solo está disponible para la unidad de traducción en la que está incluido. Sin embargo, esto oculta el problema real. Sugeriría mover la definición de la función a su propio archivo de implementación pero mantener la declaración en el encabezado.

+0

Gracias por la respuesta. Lo ordené –

+0

@dirkgently ... pero boost es solo encabezado IIRC, quizás otras librerías también. ¿Cómo evitan estos problemas? –

+1

Algo que puede ahorrarle tiempo a otros: en caso de que compile el programa C en VS, debe usar __inline para hacerlo en línea (de lo contrario fallará en la compilación) – Illidan

1
  1. La función SetPersonName serán compilados en cada objectFile que incluye el archivo Person.h, con lo que el enlazador ver varias funciones y dando el error.

  2. Al escribir estático, usted indica que la función solo será visible dentro de un solo archivo de objeto. Todavía obtendrá varias funciones en su binario, pero ahora no obtendrá los errores.

  3. tratar de escribir inline antes de la función como

    inline void SetPersonName(Person& person,const std::string name) 
    { 
        person.SetName(name); 
    } 
    

    ... porque la función es bastante simple que está bien creo tenerlo como una línea. Una línea en línea colocará el código necesario donde se usa la función, sin crear realmente una función para llamar.

1

Al declarar que la función es estática, la busca en la unidad de traducción actual, por lo que en realidad ha agregado una nueva función SetPersonName en su archivo principal, y no estaría llamando a la definida en la biblioteca.

La solución correcta es declarar SetPersonName como extern en Person.h y ponerlo en práctica en Person.cpp

Person.h

extern void SetPersonName(Person& person,const std::string name); 

Person.cpp

void SetPersonName(Person& person,const std::string name) 
{ 
    person.SetName(name); 
} 
0

Una solución sería hacer de esa función un método estático. Eso detendrá los errores "ya definidos".

3

Cuando compila su biblioteca, su archivo lib contiene una definición para SetPersonName. Cuando compila su programa que usa la biblioteca, ya que incluye el encabezado, y ha escrito el código en línea en el encabezado, también compila en una definición para SetPersonName. Dos definiciones para la misma función no están (generalmente) permitidas. La palabra clave estática le dice al compilador que la función no debe exponerse fuera de la unidad de traducción actual (pieza discreta de código que está compilando), por lo que la definición en la biblioteca no es visible para el vinculador.

La solución adecuada a este problema depende de sus objetivos. Los archivos de encabezado con declaraciones de funciones estáticas casi nunca son lo que desea. Desde el punto de vista del diseño, recomendaría deshacerse de SetPersonName por completo, y simplemente usar Person :: SetName.

Sin embargo, a falta de eso, lo implementaría de forma muy similar a como lo hizo para el resto de su funcionalidad, las declaraciones en el encabezado y la implementación en .cpp. Las funciones en línea asociadas con una biblioteca tenderán a disminuir muchas de las ventajas de usar una biblioteca en primer lugar.

0

Tuve una situación similar a la descrita claramente por @ logan-capaldo arriba.

Un archivo fuente CPP (myfile.cpp) contenía una función MyFunction. Al compilar, esto se compiló en myfile.obj. Pero el archivo principal de CPP (main.cpp) también incluía myfile.cpp, por lo que la función MyFunction se incluía/compilaba/vinculaba dos veces, lo que provocaba el error "LNK2005 ya definido".

Esto es complicado pero no tuve tiempo de arreglarlo correctamente. La solución más rápida (en VS Express 2012) era hacer clic derecho en myfile.cpp en Solution Explorer, ir a Propiedades y cambiar Excluded From Build a Yes. Supongo que esto impide que uno de los archivos OBJ se cree y/o vincule, por lo que se elimina el error.

Cuestiones relacionadas