2011-03-17 20 views
5

Soy un principiante en C++ pero tengo cierta experiencia en el uso de Java. Estoy recibiendo algunos errores que no entiendo. Adjunté una imagen de la consola de error y el código debajo de ella.¿Por qué recibo estos errores de vinculador 'ya definidos'?

Error 1 error LNK2005: "public: __thiscall VectorDouble::VectorDouble(void)" ([email protected]@[email protected]) already defined in Main.obj C:\Users\carrea\Code\Visual Studio\COMP201\Lab8_VectorDoubleClass\VectorDouble.obj Lab8_VectorDoubleClass 

Error 2 error LNK2005: "public: __thiscall VectorDouble::VectorDouble(int)" ([email protected]@[email protected]@Z) already defined in Main.obj C:\Users\carrea\Code\Visual Studio\COMP201\Lab8_VectorDoubleClass\VectorDouble.obj Lab8_VectorDoubleClass 
....  

10 errores más como estos y

Error 13 error LNK1169: one or more multiply defined symbols found C:\Users\carrea\Code\Visual Studio\COMP201\Lab8_VectorDoubleClass\Debug\Lab8_VectorDoubleClass.exe 1 1 Lab8_VectorDoubleClass 

Main.cpp


#include "VectorDouble.cpp" 
using namespace std; 
void printVD(const VectorDouble& v); 
int main() 
{ 
    VectorDouble p; 
    p.push_back(1); 
    p.push_back(4); 
    p.push_back(3); 
    VectorDouble v(p); 
    printVD(v); 
    printVD(p); 
} 
void printVD(const VectorDouble& v) 
{ 
    int n = v.size(); 
    for(int i = 0; i<n; i++) 
    { 
     cout << v.getElementAt(n) << " "; 
    } 
    cout << endl; 
} 

VectorDouble.h


#pragma once 
#include <fstream> 
#include <iostream> 
#include <string> 
#include <cstdlib> 
#include <iomanip> 
#include <vector> 
#include <sstream> 
using namespace std; 
class VectorDouble 
{ 
public: 
    VectorDouble(void); 
    ~VectorDouble(void); 
    VectorDouble(int intSize); 
    // Copy constructor 
    VectorDouble(const VectorDouble& vd); 
    // = override 
    void operator =(const VectorDouble& RIGHT_SIDE); 
private: 
    double *dArray; 
    int count, max_count; 
public: 
    // returns number of occupied cells 
    int size(void) const; 
    // Returns total number of cells 
    int capacity(void) const; 
    // Adds an element to array 
    void push_back(double num); 
    // Resizes the array to be double the original max_count 
    void resize(void); 
    // Returns element at specified index 
    double getElementAt(int i) const; 
    // Requests that the capacity of the allocated storage space for the elements of the vector container be at least enough to hold n elements 
    void reserve(int n); 
private: 
    // Sets every element to 0 
    void clear(void); 
}; 

VectorDouble.cpp


#pragma once 
#include "VectorDouble.h" 

using namespace std; 

VectorDouble::VectorDouble(void) 
{ 
    max_count = 100; 
    count = 0; 
    dArray = new double[max_count]; 
    clear(); 
} 

VectorDouble::VectorDouble(int intSize) 
{ 
    max_count = intSize; 
    dArray = new double[max_count]; 
    clear(); 
} 

VectorDouble::~VectorDouble(void) 
{ 
    cout << "vector with " << this->count << " is destroyed"; 
} 

// Copy constructor 
VectorDouble::VectorDouble(const VectorDouble& vd) 
{ 
    int mcVD = vd.capacity(), i=0; 
    max_count = mcVD; 
    dArray = new double[max_count]; 
    clear(); 
    while(i<max_count) 
    { 
     dArray[i] = vd.getElementAt(i); 
     i++; 
    } 
} 
// = override 
void VectorDouble::operator =(const VectorDouble& RIGHT_SIDE) 
{ 
    int rightCount = RIGHT_SIDE.size(), i=0; 
    while(rightCount>max_count) 
    { 
     resize(); 
    } 
    while(i<rightCount) 
    { 
     dArray[i] = RIGHT_SIDE.getElementAt(i); 
     i++; 
    } 
    count = i; 
} 
// returns number of occupied cells 
int VectorDouble::size(void) const 
{ 
    return count; 
} 
// Returns total number of cells 
int VectorDouble::capacity(void) const 
{ 
    return max_count; 
} 
// Adds an element to array 
void VectorDouble::push_back(double num) 
{ 
    if(count==max_count) 
    { 
     resize(); 
    } 
    dArray[count] = num; 
    count++; 
} 
// Resizes the array to be double the original max_count 
void VectorDouble::resize(void) 
{ 
    double *p = new double[max_count*2]; 
    for(int i = 0; i < count; i++) 
    { 
     p[i] = dArray[i]; 
    } 
    dArray = p; 
    max_count*=2; 
    delete p; 
} 


// Returns element at specified index 
double VectorDouble::getElementAt(int i) const 
{ 
    return dArray[i]; 
} 


// Requests that the capacity of the allocated storage space for the elements of the vector container be at least enough to hold n elements 
void VectorDouble::reserve(int n) 
{ 
    while(n<max_count) 
     resize(); 
} 


// Sets every element to 0 
void VectorDouble::clear(void) 
{ 
    for(int i = 0; i < max_count; i++) 
     dArray[i] = 0; 
} 

Cualquier ayuda sería muy apreciada ...

+8

no en caso de que # include "VectorDouble.h" en main.cpp en lugar de "VectorDouble.cpp"? –

+0

Mover a CodeReview.SE? –

+0

También la copia de la asignación no se ha implementado correctamente ('void operator = (const VectorDouble & RIGHT_SIDE);'). Se supone que devuelve una referencia, en general. – Mahesh

Respuesta

26

Debe incluir "VectorDouble.h" y no "VectorDouble.cpp" en Main.cpp.

Todo el concepto de incluir archivos está bastante roto en C++ en comparación con muchos otros idiomas.

Primero C++ divide las cosas en 'declaraciones' y 'definiciones'. Puede que solo tenga una definición de algo en un programa, pero tantas declaraciones como desee. En su archivo VectorDouble.cpp está definiendo cosas, y en el archivo VectorDouble.h está declarando cosas.

La directiva #include en C++ es muy simple y estúpida. Cuando se encuentra, el compilador realiza un reemplazo de texto simple. La directiva #include se reemplaza con el contenido del archivo que está incluyendo.

Cuando usted #include un archivo de definiciones, eso significa que efectivamente las define allí donde ha hecho el #include. Es por eso que no debe incluir "VectorDouble.cpp". Como probablemente también compile ese archivo como un archivo separado, entonces termina con al menos dos copias de todas las definiciones allí.

Esta dicotomía declaración completa frente a definición se vuelve muy confusa cuando se habla de ciertos tipos de cosas. Por ejemplo, si se declara una función inline, el cuerpo de la función ya no se considera realmente un definition, exactamente. Esto significa que puede tener tantas copias de un cuerpo de función que haya sido declarado inline como lo desee. Todo lo que se requiere es que todas las definiciones sean idénticas.

De manera similar, declarar una función de plantilla es una declaración, incluso si incluye un cuerpo de función. Esto se debe a que la declaración no genera ningún código, solo la instanciación de la plantilla da como resultado la generación de código. Y esa es la verdadera prueba de fuego para decidir si algo es una declaración o definición. Si da lugar a que se asigne espacio o se produzca un código real en ese mismo momento, entonces es una definición, de lo contrario es una declaración.

6

El error que está recibiendo es un error de vinculador que que el compilador es encontrar múltiples definiciones para contar ciertas funciones miembro Si nos fijamos en este trozo del mensaje de error:

public: __thiscall VectorDouble::VectorDouble(void)" ([email protected]@[email protected]) already defined in Main.obj 

Usted puede ver que hay enterrado en el hecho de que está hablando el constructor VectorDouble::VectorDouble() ya se está definiendo.

creo que el problema particular que se está ejecutando en es en esta línea en main.cpp:

#include "VectorDouble.cpp" 

El problema es que esto incluye el archivo fuente , no el encabezado del archivo . En consecuencia, cuando compila main.cpp, compilará todos los principales, más todas las definiciones en VectorDouble.cpp. Cuando el enlazador intenta vincular esto con el archivo objeto generado cuando compiló VectorDouble.cpp, encontrará dos definiciones de todo: una de VectorDouble.cpp y otra de main.cpp.

Para solucionar este problema, cambiar esta línea para leer

#include "VectorDouble.h" 

Eso debería resolver su problema. En términos más generales, sin embargo, es extremadamente raro en realidad #include un archivo .cpp. Casi siempre incluye encabezados, no fuentes.

Espero que esto ayude!

+1

No creo que esta sea una respuesta muy buena (aunque no -1 no es buena) porque no explica por qué hay archivos 'fuente' y 'encabezado'.Esta es una distinción muy extraña, y entre los lenguajes modernos de uso común, solo existe en C y C++. Merece una explicación, especialmente para alguien que es un programador de Java. – Omnifarious

+0

No es una distinción extraña, y está presente de alguna forma en todos los idiomas diseñados para programación a gran escala. Por lo general, desea mantener la interfaz especificada en un archivo separado de la implementación. –

+0

@James Kanze: no existe en Java, ni en Python, Ruby, perl, PHP, lisp, erlang u OCaml. De hecho, en todos los idiomas que he usado para algo serio en los últimos 10 años, C y C++ han sido los únicos que han tenido la distinción. – Omnifarious

1

Main.cpp no ​​debería ser #include -ing VectorDouble.cpp; debería #include VectorDouble.h. Si está vinculando ambos archivos .cpp, el vinculador ve todo en VectorDouble.cpp dos veces (una sola vez, y una vez cuando es #include -d desde Main.cpp).

0

tengo un error de enlace similar cuando traté de definir una clase en un archivo separado llamado PresentDataStruct.h y también creó un archivo PresentDataStruct.cpp.

Éstos son los contenidos de PresentDataStruct.h:

#pragma once 

#include <string> 
using namespace System; 
ref class CPresentDataStruct 
{ 
public: 
    CPresentDataStruct(); 
    ~CPresentDataStruct(); 

public: 
    void SomeActionOnData(); 

public: 

    System::String^ Name; 
    DateTime^ BirthDay; 

}; 

void CPresentDataStruct::SomeActionOnData() 
{ 
    //TO DO here 
} 

CPresentDataStruct::CPresentDataStruct() 
{ 
} 

CPresentDataStruct::~CPresentDataStruct() 
{ 
} 

Mientras que en PresentDataStruct.cpp tiene una línea:

include "PresentDataStruct.h" 

A continuación, aparece el error de enlace cuando agrego include "PresentDataStruct.h" en el archivo maindialog.h.

Así que se trasladó a este archivo PresentDataStruct.cpp y el error de enlace desaparecieron:

void CPresentDataStruct::SomeActionOnData() 
{ 
    //TO DO here 
} 

CPresentDataStruct::CPresentDataStruct() 
{ 
} 

CPresentDataStruct::~CPresentDataStruct() 
{ 
} 
Cuestiones relacionadas