Переменная уже определена в .obj;Что здесь происходит? - PullRequest
2 голосов
/ 24 июня 2019

head.h


#pragma once

namespace foo
{
    int bar;

    int funct1();
}

head.cpp

#include "head.h"

int foo::funct1()
{
    return bar;
}

main.cpp

#include <iostream>

#include "head.h"


int main()
{
    foo::bar = 1;
    std::cout << foo::funct1() << std::endl;
    return 0;
}

Ошибка LNK2005 "int foo :: bar" (?bar @ foo @@ 3HA) уже определено в head.obj

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

Я не включаю файлы .cpp в main.Я ничего не переопределяю.Я буквально просто присваиваю 1 переменной, а затем возвращаю ее функцией в том же пространстве именКак это определяется несколько раз?

Ответы [ 7 ]

5 голосов
/ 24 июня 2019

Заголовок head.h входит в две единицы компиляции head.cpp и main.cpp.Таким образом, переменная bar определяется дважды.Вы можете объявить переменную без ее определения следующим образом

#pragma once

namespace foo
{
    extern int bar;

    int funct1();
}

и затем определить ее в некотором модуле cpp.

4 голосов
/ 24 июня 2019

Это foo уровень пространства имен bar объявление:

namespace foo
{
    int bar;
}

на самом деле определение .

Чтобы сделать его объявлением, отметьте bar как extern в head.h :

namespace foo
{
    extern int bar;
}

Затем определите его в head.cpp :

int foo::bar = 0;
2 голосов
/ 24 июня 2019

Я ничего не переопределяю. Я буквально просто присваиваю 1 переменной

Вы переопределяете переменную!

head.cpp имеет один через #include "head.h", а main.cpp имеет один через #include "head.h".

Вам нужно просто объявить это (необычно, но не слишком странно) в шапке:

extern int bar;

& hellip; затем определите его в одну единицу перевода. Это похоже на то, что вы делаете с static членами класса (хотя и с немного другим синтаксисом).

Начиная с C ++ 17, вы можете сделать это, вместо этого добавив ключевое слово inline в ваше определение .

В качестве альтернативы, избегайте изменчивых глобалов & hellip;

2 голосов
/ 24 июня 2019

Как это определяется несколько раз?

Он определяется один раз в head.cpp и один раз в main.cpp. Это в общей сложности два раза. Это нарушает одно правило определения, согласно которому для каждой переменной может быть только одно определение.

int bar;

Это определение переменной. Вы включили его в две единицы перевода.

Переменная может быть объявлена ​​без определения во внешнем объявлении:

extern int bar;

Замените определение таким объявлением и поместите определение ровно в одну единицу перевода.

2 голосов
/ 24 июня 2019

head.h включено в и main.cpp и head.cpp.Таким образом, переменная определяется дважды.

Возможное решение: сделать ее встроенной.«Внешние» решения тоже хороши, хотя и более старые в подходе.

namespace foo
{
    inline int bar;
}
1 голос
/ 26 июня 2019

Обратите внимание, что foo - это не класс, а пространство имен. Когда вы объявляете свободную переменную в заголовочном файле:

int bar;

И затем #include этот заголовочный файл несколько раз (в разных файлах CPP, вызывая несколько компиляций модуля перевода), вы получите ошибку компоновщика. Все это знают.

И вы добавите атрибут extern в объявление, а определите переменную в другом месте в одном из файлов CPP / C.

Помещение глобальной переменной в пространство имен - это не что иное, как присвоение переменной global другого имени. Подумайте, если foo::bar как foo__NS__bar, и, следовательно, вы должны добавить extern в заголовок и определить foo::bar в некотором местоположении.

Обратите внимание, что это отличается от нестатической переменной-члена класса. Переменная класса не должна быть определена / объявлена ​​таким образом, поскольку класс является типом . Каждая экземплярная переменная класса-типа будет иметь отдельную копию переменной. Кроме того, когда вы добавляете переменную static в класс, вы даете этой переменной логически global другое имя. Следовательно, у вас должна быть эта статическая переменная , определенная , в одном из файлов CPP.

0 голосов
/ 24 июня 2019

Проблема в том, что вы определяете foo :: bar более одного раза: в header.h и main.cpp.Это глобальная переменная, которая определяется более одного раза, и это невозможно.Поэтому компоновщик жалуется, что вы определяете его несколько раз.

Это можно исправить, объявив foo :: bar с extern:

namespace foo
{
    extern int bar;

    int funct1();
}

Затем определите его в header.cpp:

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