Ошибка C++ LNK2005 при добавлении нового заголовочного файла
Я работаю над проектом для школы. Я знаю о своей циклической зависимости (и я прочитал большинство резолюций здесь для этого ранее), но в настоящее время она работает так, как мне нужно. К сожалению, я почти уверен, что это также причина моих бед. Я хотел бы включить concol.h
чтобы его можно было использовать с обоими файлами (я хотел бы добавить немного цвета к своему выводу - не требование для моего назначения, а то, что я хотел бы сделать). Я пробовал разместить этот файл заголовка в нескольких разных местах, и я всегда получаю одни и те же ошибки. Я решил использовать предварительное объявление, как и для работы с циклической зависимостью, но я не думаю, что это будет работать с пространством имен.
Ошибки:
1>Flight.obj : error LNK2005: "void * eku::std_con_out" (?std_con_out@eku@@3PAXA) already defined in BoardingPass.obj
1>Flight.obj : error LNK2005: "bool eku::colorprotect" (?colorprotect@eku@@3_NA) already defined in BoardingPass.obj
1>Flight.obj : error LNK2005: "enum eku::concol eku::textcol" (?textcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>Flight.obj : error LNK2005: "enum eku::concol eku::backcol" (?backcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>Flight.obj : error LNK2005: "enum eku::concol eku::deftextcol" (?deftextcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>Flight.obj : error LNK2005: "enum eku::concol eku::defbackcol" (?defbackcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>Source.obj : error LNK2005: "void * eku::std_con_out" (?std_con_out@eku@@3PAXA) already defined in BoardingPass.obj
1>Source.obj : error LNK2005: "bool eku::colorprotect" (?colorprotect@eku@@3_NA) already defined in BoardingPass.obj
1>Source.obj : error LNK2005: "enum eku::concol eku::textcol" (?textcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>Source.obj : error LNK2005: "enum eku::concol eku::backcol" (?backcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>Source.obj : error LNK2005: "enum eku::concol eku::deftextcol" (?deftextcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>Source.obj : error LNK2005: "enum eku::concol eku::defbackcol" (?defbackcol@eku@@3W4concol@1@A) already defined in BoardingPass.obj
1>D:\School Stuff\Fall 2015\CIST 2362 C++ II\Final - Airline Reservation System\Debug\Final - Airline Reservation System.exe : fatal error LNK1169: one or more multiply defined symbols found
Source.cpp
#include <fstream>
#include <iostream>
#include <iomanip>
#include "FlightComparators.h" //includes Flight.h
#include "LocationComparators.h"
//prototypes
//methods
Flight.h
#ifndef FLIGHT_H
#define FLIGHT_H
#ifndef BOARDINGPASS_H
#include "BoardingPass.h"
#endif
#include <algorithm>
#include <string>
#include <vector>
#include "Location.h"
#include "Validate.h"
#include "AirlineTypeA.h"
#include "AirlineTypeB.h"
class BoardingPass;
class Flight{
private:
Location *departureLoc;
Location *destinationLoc;
char departureTime[6];
char arrivalTime[6];
int number;
int freqFlyerMiles;
int curOccupancy = 0;
Airline *plane;
vector<BoardingPass*> passengers;
public:
//constructor
Flight(Location*, Location*, string, string, int, int, char type);
//getters
Location* getDepartureLoc(){ return departureLoc; }
Location* getDestinationLoc(){ return destinationLoc; }
int getFlightNumber(){ return number; }
int getFreqFlyerMiles(){ return freqFlyerMiles; }
string getDepTime(){ return departureTime; }
string getAriTime(){ return arrivalTime; }
int getCurOccupancy(){ return curOccupancy; }
Airline* getPlane(){ return plane; }
vector<BoardingPass*> getPassengerList(){ return passengers; }
bool getIsFull(){ return this->plane->getMaxPass() > curOccupancy; }
void addPass(string, string, string);
void cancelReservation(int);
void displayPassengers();
void sortPassengers();
};
#endif
BoardingPass.h
#ifndef BOARDINGPASS_H
#define BOARDINGPASS_H
#ifndef FLIGHT_H
#include "Flight.h"
#endif
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class Flight;
class BoardingPass{
private:
string fName;
string lName;
Flight* flight;
string seat;
public:
BoardingPass(string, string, Flight *flt, string seat);
string getFName(){ return fName; }
string getLName(){ return lName; }
string getSeat(){ return seat; }
void displayBoardingPass();
void writeBoardingPass(fstream&);
};
#endif
concol.h
#ifndef INC_EKU_IO_CONCOL
#define INC_EKU_IO_CONCOL
/*Header file to color text and background in windows console applications
Global variables - textcol,backcol,deftextcol,defbackcol,colorprotect*/
#include<windows.h>
#include<iosfwd>
namespace eku
{
#ifndef CONCOL
#define CONCOL
enum concol
{
black = 0,
dark_blue = 1,
dark_green = 2,
dark_aqua, dark_cyan = 3,
dark_red = 4,
dark_purple = 5, dark_pink = 5, dark_magenta = 5,
dark_yellow = 6,
dark_white = 7,
gray = 8,
blue = 9,
green = 10,
aqua = 11, cyan = 11,
red = 12,
purple = 13, pink = 13, magenta = 13,
yellow = 14,
white = 15
};
#endif //CONCOL
HANDLE std_con_out;
//Standard Output Handle
bool colorprotect = false;
//If colorprotect is true, background and text colors will never be the same
concol textcol, backcol, deftextcol, defbackcol;
/*textcol - current text color
backcol - current back color
deftextcol - original text color
defbackcol - original back color*/
inline void update_colors()
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(std_con_out, &csbi);
textcol = concol(csbi.wAttributes & 15);
backcol = concol((csbi.wAttributes & 0xf0) >> 4);
}
inline void setcolor(concol textcolor, concol backcolor)
{
if (colorprotect && textcolor == backcolor)return;
textcol = textcolor; backcol = backcolor;
unsigned short wAttributes = ((unsigned int)backcol << 4) | (unsigned int)textcol;
SetConsoleTextAttribute(std_con_out, wAttributes);
}
inline void settextcolor(concol textcolor)
{
if (colorprotect && textcolor == backcol)return;
textcol = textcolor;
unsigned short wAttributes = ((unsigned int)backcol << 4) | (unsigned int)textcol;
SetConsoleTextAttribute(std_con_out, wAttributes);
}
inline void setbackcolor(concol backcolor)
{
if (colorprotect && textcol == backcolor)return;
backcol = backcolor;
unsigned short wAttributes = ((unsigned int)backcol << 4) | (unsigned int)textcol;
SetConsoleTextAttribute(std_con_out, wAttributes);
}
inline void concolinit()
{
std_con_out = GetStdHandle(STD_OUTPUT_HANDLE);
update_colors();
deftextcol = textcol; defbackcol = backcol;
}
template<class elem, class traits>
inline std::basic_ostream<elem, traits>& operator<<(std::basic_ostream<elem, traits>& os, concol col)
{
os.flush(); settextcolor(col); return os;
}
template<class elem, class traits>
inline std::basic_istream<elem, traits>& operator>>(std::basic_istream<elem, traits>& is, concol col)
{
std::basic_ostream<elem, traits>* p = is.tie();
if (p != NULL)p->flush();
settextcolor(col);
return is;
}
} //end of namespace eku
#endif //INC_EKU_IO_CONCOL
2 ответа
В concol.h
вы определяете переменные внутри пространства имен, а не объявляете их. Переменные должны быть extern
издание
extern HANDLE std_con_out;
в заголовке (чтобы определить их), затем объявлен (без extern) в файле.cpp (concol.cpp).
Символы, указанные компоновщиком как "уже определенные", являются элементами, которые объявлены в заголовочных файлах, но вне какого-либо класса. (В "области видимости файла".) В результате каждый файл.cpp, который включает эти заголовочные файлы, пытается переопределить хранилище для них. Когда компоновщик пытается связать объектные файлы вместе, он видит эти множественные определения и жалуется на них.
Лучшее, что нужно сделать, чтобы решить вашу проблему, это сделать все эти элементы "членами статических данных" класса. Это означает, что они должны быть объявлены в классе и помечены как static
,
Если вы не хотите перемещать их внутри класса, вы должны следить за тем, чтобы они были объявлены как "внешние", когда включены во все файлы.cpp, кроме одного. Таким образом, только один файл.cpp попытается определить хранилище для них, и компоновщик будет счастлив.
Обычно это делается следующим образом:
a.cpp:
#define DECLARE_STORAGE
#include "myheader.h"
b.cpp, c.cpp и т. д.
#include "myheader.h" //without defining DECLARE_STORAGE
myheader.h
#ifdef DECLARE_STORAGE
#define POSSIBLY_EXTERN
#else
#define POSSIBLY_EXTERN extern
#endif
POSSIBLY_EXTERN int my_integer;
это заставит a.cpp скомпилировать оператор
int my_integer;
в то время как b.cpp, c.cpp и т. д. скомпилируют оператор
extern int my_integer;