2011-03-17 86 views
5

我是C++的初學者,但我有一些使用Java的經驗。我收到一些我不明白的錯誤。我附上了錯誤控制檯的圖片和它下面的代碼。爲什麼我得到這些'已經定義'的鏈接器錯誤?

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個更多的錯誤喜歡這些和

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; 
} 

任何幫助,將不勝感激......

+8

你不應該#包括「VectorDouble.h」? – 2011-03-17 00:20:17

+0

轉到CodeReview.SE? – 2011-03-17 00:21:19

+0

複製分配沒有正確實現('void operator =(const VectorDouble&RIGHT_SIDE);')。一般來說,它應該返回一個參考。 – Mahesh 2011-03-17 00:27:36

回答

26

您應該在Main.cpp中包含"VectorDouble.h"而不是"VectorDouble.cpp"

與許多其他語言相比,包含文件的整個概念在C++中相當破碎。第一個C++將事物分成'聲明'和'定義'。你可能只有一個程序中的某個定義,但只要你想要的聲明。在你的VectorDouble.cpp文件中你正在定義的東西,並在VectorDouble.h文件中聲明的東西。

C++中的#include指令簡直太愚蠢了。遇到它時,編譯器會有效地進行簡單的文本替換。 #include指令被替換爲您所包含文件的內容。

當你有一個定義的文件,這意味着你有效地定義它們在那裏你已經完成了#include。這就是爲什麼你不應該包括"VectorDouble.cpp"。由於您可能還會將該文件作爲單獨的文件進行編譯,因此您至少會在這裏得到至少兩個所有定義的副本。

整個聲明與定義二分法在討論某些事物時變得非常混亂。例如,如果一個函數被聲明爲inline,那麼函數體不再被認爲是definition。這意味着您可以擁有任意數量的已聲明爲inline的函數體副本。所有需要的是所有的定義都是相同的。

同樣,即使包含函數體,聲明模板函數也是聲明。這是因爲聲明導致沒有生成代碼,只有模板實例化導致代碼生成。這是決定是否有聲明或定義的真正考驗。如果它導致分配空間或實際編碼正確,那麼它就是一個定義,否則它就是一個聲明。

6

你得到的錯誤是連接錯誤,告訴你,編譯器是找到多個定義某些成員功能。如果你看一下這個塊的錯誤消息:

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

你可以看到埋在那裏的事實,它在談論已經被定義構造函數VectorDouble::VectorDouble()

我認爲你正在運行到特定的問題是在這條線在main.cpp中:

#include "VectorDouble.cpp" 

的問題是,這包括文件,而不是文件。因此,當您編譯main.cpp時,您將編譯所有main,以及VectorDouble.cpp中的所有定義。當鏈接器嘗試將它與編譯VectorDouble.cpp時生成的目標文件鏈接起來時,它會找到所有內容的兩個定義 - 一個來自VectorDouble.cpp,一個來自main.cpp。

爲了解決這個問題,更改此行以讀取

#include "VectorDouble.h" 

這應該解決您的問題。但更普遍的是,實際上#include a .cpp文件非常罕見。你幾乎總是包含標題,而不是來源。

希望這會有所幫助!

+1

我不認爲這是一個非常好的答案(雖然不是-1),因爲它不能解釋爲什麼有'源'文件和'頭'文件。這是一個非常古怪的區別,在現代常用語言中大多隻存在於C和C++中。它值得解釋,特別是對於一個Java程序員來說。 – Omnifarious 2011-03-17 04:16:24

+0

這不是一個奇怪的區別,並以某種形式出現在用於大規模編程的所有語言中。您通常希望將實現中指定的接口保存在單獨的文件中。 – 2011-03-17 11:36:00

+0

@James Kanze:它不存在於Java中,也不存在於Python,Ruby,perl,PHP或lisp,erlang或OCaml中。事實上,在過去10年裏我用過的所有語言都是嚴肅認真的語言,而C和C++是唯一有這種區別的語言。 – Omnifarious 2011-03-17 18:01:54

1

Main.cpp不應該是#include -ing VectorDouble.cpp;它應該是#include VectorDouble.h。如果您鏈接了兩個.cpp文件,鏈接器將在VectorDouble.cpp中看到所有內容(一次是自己的,一次是從Main.cpp發出的#include -d)。

0

我有一個類似的鏈接錯誤,當我試圖在一個名爲PresentDataStruct.h一個單獨的文件來定義一個類,還創建了一個PresentDataStruct.cpp文件。

這裏是內容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() 
{ 
} 

雖然PresentDataStruct.cpp有一行:

include "PresentDataStruct.h" 

後來,當我加入include "PresentDataStruct.h"出現鏈接錯誤 到maindialog.h文件。

所以我搬到這PresentDataStruct.cpp文件和鏈接錯誤消失:在main.cpp中,而不是「VectorDouble.cpp」

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

CPresentDataStruct::CPresentDataStruct() 
{ 
} 

CPresentDataStruct::~CPresentDataStruct() 
{ 
}