Несколько объявлений против не определены - PullRequest
1 голос
/ 16 марта 2019

Я пытаюсь импортировать переменные из файла, которые используются в классе в другом файле, и в конечном итоге импортировать их в еще один файл и скомпилировать.

Позвольте мне показать, как выглядит воспроизведение проблемы:

  • 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, но мне не удается это сделать.

Если я не включу arrayFile.cpp в mainfile.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 ]

3 голосов
/ 16 марта 2019

В целом, не рекомендуется определять переменные в заголовочном файле - при условии, что указанный заголовочный файл будет включен в несколько исходных файлов.

Когда вы компилируете свой проект, препроцессор обрабатывает операторы "#include", буквально помещая содержимое включенного заголовочного файла в файл, включающий его. E.g.:

// 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.hpp, которое включено classFile.cpp и mainfile.cpp. Может быть полезно рассмотреть дерево включения:

           arrayFile.hpp
                |
           classFile.hpp
             /       \
   classFile.cpp    mainfile.cpp

Подумайте о том, что я сказал RE: заменив include s включенным содержимым файла, и посмотрите, не согласны ли вы, когда я скажу, что classFile.cpp и mainfile.cpp оба заканчиваются на определение вашего arr массива.

Что будет дальше, когда вы компилируете свой проект? Компилятор компилирует ваш исходный код - , в частности, вывод препроцессора - в объектные файлы. Например. предварительно обработанный classFile.cpp становится classFile.o, а предварительно обработанный mainfile.cpp становится mainfile.o.

Наконец, объектные файлы (или библиотеки, в которые они архивируются) связаны для формирования вашего исполняемого файла.

Когда компоновщик пытается связать classFile.o и mainfile.o, он обнаруживает, что оба имеют arr, определенные в них. Таким образом, вы получаете множественное определение ошибка компоновщика - не ошибка компилятора .

Итак: если заголовочный файл включен - прямо или косвенно - несколькими исходными файлами, вы столкнетесь с ошибками компоновщика , если заголовочный файл определит переменные. Вот почему стандартная практика объявлять переменные в заголовочных файлах и определять их в одном исходном файле.

Надеюсь, это поможет.

3 голосов
/ 16 марта 2019

Вы не должны включать arrayFile.hpp в ваш classFile.hpp. Включите его только в classFile.cpp. Также в mainfile.cpp (перед основной функцией) добавьте строку

extern int arr[];

Эта строка сообщает компиляторам, что массив типа int с именем "arr" будет определен в каком-либо другом файле 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...