多重声明与未定义

时间:2019-03-16 16:58:44

标签: c++ c++11

我正试图从文件中导入用于其他文件中的类的变量,并最终将其导入另一个文件并进行编译。

让我展示问题的重现情况:

  • arrayFile.hpp

    int arr[] = {
      1,2,6,5,4,3
    };
    
  • classFile.hpp

    #include <iostream>
    
    using namespace std;
    
    #include "arrayFile.hpp"
    
    class MyClass{
    private:
        int v1;  
    
    public:
        MyClass();
        void setV(int v);
        int getV();
        int funcM();
    };
    
  • classFile.cpp

    #include <iostream>
    using namespace std;
    
    #include "classFile.hpp"
    
    MyClass::MyClass(){};
    
    void MyClass::setV(int v){
       v1 = v;
    }
    
    int MyClass::getV(){
       return v1;
    }
    
    int MyClass::funcM(){
       return v1*arr[0];
    }
    
  • mainfile.cpp

    #include <iostream>
    using namespace std;
    
    #include "classFolder/classFile.hpp"
    
    // #include "classFolder/arrayFile.hpp"
    // should i include this?
    
    int main(){
    
        MyClass c;
    
        c.setV(3);
        cout<<c.funcM()<<endl;
    
        cout<<arr[0]<<'*'<<c.getV()<<endl;
    
    }
    

目标是从classFile.cpp和mainfile.cpp中访问数组,但是我没有做到这一点。

如果我在mainfile.cpp中不包含arrayFile.cpp:

/tmp/cce4ZHbp.o:(.data+0x0): multiple definition of `arr'
/tmp/ccmsYdmt.o:(.data+0x0): first defined here

如果我这样做:

In file included from mainfile.cpp:5:0:
classFolder/arrayFile.hpp:1:9: error: redefinition of ‘int arr []’
 int arr[] = {
         ^
In file included from classFolder/classFile.hpp:3:0,
                 from mainfile.cpp:4:
classFolder/arrayFile.hpp:1:5: note: ‘int arr [6]’ previously defined here
 int arr[] = {
     ^

我能够让编译器告诉我arr []也未定义,但是无法重现此错误。

我在做什么错?

我面临的真正问题是需要将一个数组和一个结构导入一个类,并且将该类导入另一个更大的类,最后一个类最终由main使用。这是我最擅长的。我不知道该如何解决。

2 个答案:

答案 0 :(得分:3)

您不应在classFile.hpp中包含arrayFile.hpp。仅将其包括在classFile.cpp中。另外,在mainfile.cpp中(在主函数之前)添加行

extern int arr[];

此行告诉编译器,将在其他cpp文件中定义名为int类型的数组,该cpp文件将与mainfile.cpp链接在一起。

像这样编译程序:

g++ -std=c++11 -c main.cpp classFile.cpp
g++ -std=c++11 main.o classFile.o
./a.out

第一行分别编译文件(创建main.o和classFile.o文件) 第二行将它们链接在一起,创建一个可执行文件(a.out) 第三行运行可执行文件

由于添加新文件会使此编译过程变得复杂,因此建议使用Makefile。

答案 1 :(得分:3)

广泛地说,定义头文件中的变量不是一个好主意-假设所述头文件将被多个源文件包含。

编译项目时,预处理器通过将包含的头文件的内容逐字放置在包含它的文件中来处理“ #include”语句。 例如:

// foo.h
#ifndef FOO_H
#define FOO_H
typedef int myInt;
#endif

// main.cpp
#include "foo.h"
int main( int argc, char* argv[] )
{
  return 0;
}

// preprocessor output

typedef int myInt;

int main( int argc, char* argv[] )
{
  return 0;
}

这是一个简化-但足以用于说明目的。 那么您的示例中发生了什么? arrayFile.hpp包含classFile.hppclassFile.cppmainfile.cpp包含 arrayFile.hpp | classFile.hpp / \ classFile.cpp mainfile.cpp 。考虑包含树可能会有所帮助:

include

想一想我说的RE:用随附的文件内容替换classFile.cpp,看看我是否mainfile.cpparr都是< / em>以classFile.cpp数组的定义结尾。

编译项目时,接下来会发生什么?编译器将您的源代码(特别是预处理器输出)编译为目标文件。例如。预处理的classFile.o变成mainfile.cpp,预处理的mainfile.o变成classFile.o

最后,对象文件(或归档到它们的库)被链接以形成可执行文件。

当链接器尝试链接mainfile.oarr时,会发现两个 中都定义了 Dim oDom As Object: Set oDom = CreateObject("htmlFile") Dim x As Long, y As Long Dim oRow As Object, oCell As Object Dim vData As Variant Dim link As String link = "https://www.marketscreener.com/COLUMBIA-SPORTSWEAR-COMPA-8859/company/" y = 1: x = 1 With CreateObject("msxml2.xmlhttp") .Open "GET", link, False .send oDom.body.innerHTML = .responseText End With With oDom.getElementsByTagName("table")(25) ReDim vData(1 To .Rows.Length, 1 To 11) '.Rows(1).Cells.Length) For Each oRow In .Rows For Each oCell In oRow.Cells vData(x, y) = oCell.innerText y = y + 1 Next oCell y = 1 x = x + 1 Next oRow End With Sheets(2).Cells(66, 2).Resize(UBound(vData), UBound(vData, 2)).Value = vData 。因此,您将得到多个定义链接器错误-而不是编译器错误

因此:如果头文件直接或间接包含在多个源文件中,则如果头文件定义变量,则会遇到链接器错误。这就是为什么通常的做法是在头文件中声明并在一个源文件中定义

希望有帮助。