Already defined Obj? Linking error?

2020-02-29 03:23发布

问题:

I can't for the life of me figure out why I am getting these errors, especially since I have include guards.

These are my errors (please ignore what I named my computer):

1>main.obj : error LNK2005: "class std::basic_ostream > >& __cdecl operator<<(class std::basic_ostream > &,class >Date &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAVDate@@@Z) already >defined in loan.obj

1>main.obj : error LNK2005: "class std::basic_ostream > >& __cdecl operator<<(class std::basic_ostream > &,class >Loan &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAVLoan@@@Z) already >defined in loan.obj

1>C:\Users\SweetAssSarah\Documents\Visual Studio >2012\Projects\ConsoleApplication4\Debug\a1.exe : fatal error LNK1169: one or more multiply >defined symbols found

And here are my 4 files: Main.cpp:

#ifndef _main_cpp
#define _main_cpp

#include<iostream>
#include "loan.h"
#include "date.h"

using namespace std;

void main(){
    const int MAX_SIZE = 80;
    char response[MAX_SIZE];

    Loan sarah("Sarah", "123 Awesomeville ", Date (01,February,2010));

    cout << sarah.getName() << " address: " << sarah.getAddress() << endl;
    cout << "Date: " << sarah.getDate() << endl;

    //keep console open until user types a key and enter
    cout <<"\n\n" << "Press ENTER to continue";
    cin.getline(response, MAX_SIZE);

    return;
}    
#endif

loan.cpp:

#ifndef _loan_cpp
#define _loan_cpp

#include <iostream>
#include "loan.h"
#include "date.h"

using namespace std;

Loan::Loan(char * aName, char * anAddress, Date aDate){
    name = aName;
    address = anAddress;
    date = aDate;
    cout <<"CONSTRUCTING: " << name << "\n"; 
}    
Loan::~Loan(){
    cout << "DESTRUCTING: " << name << endl;
} 
char * Loan::getName() {return  name;} 
char * Loan::getAddress(){return address;} 
Date Loan::getDate(){return date;}

void Loan:: printOn(ostream & ostr) {
    cout << name << " address: " << address << endl;
}    
#endif

loan.h:

#ifndef _loan_h
#define _loan_h

#include <math.h> //for the pow() function to do exponentiation
#include <iostream>
#include "date.h"

using namespace std;

class Loan{
public:
    Loan(char *, char *, Date );//constructor
    ~Loan();

    char * getName();
    char * getAddress();
    Date getDate();

    void printOn(ostream & ostr);
private: 
    char * name; 
    char * address;
    Date date; //requires class Date to have a default constructor

};
ostream & operator<<(ostream & ostr, Loan & aLoan) { 
    aLoan.printOn(ostr); 
    return ostr; 
}
#endif

date.h:

#ifndef _date_h
#define _date_h
#include <iostream>

enum Month {January=1, February, March, April, May, June, July, August,
September, October, November, December};

using namespace std;

class Date{
public:
//  Date() {};
    Date(int aDay = 1, Month aMonth = May, int aYear = 2005){
        day = aDay;
        month = aMonth;
        year = aYear;
}    
void printOn(ostream & o){
    o << day << "/" << month << "/" << year;
}
private:
    int day;
    Month month;
    int year;
};    
ostream & operator<<(ostream & ostr, Date & d) { 
    d.printOn(ostr); 
    return ostr; 
} 
#endif

Please help!

回答1:

As already stated in the comments, the << operator needs to be inlined or defined in the cpp file. When you define the function in the header file, it will be compiled in each cpp file where you include the header. If you include the header in more than one cpp file then you get the compiler errors because the same code will be compiled into multiple .obj files. The linker does not know which .obj file to use and throws an error.

Solution 1 - Splitting into .h and .cpp

loan.h

ostream & operator<<(ostream & ostr, Loan & aLoan);

loan.cpp

ostream & operator<<(ostream & ostr, Loan & aLoan) { 
    aLoan.printOn(ostr); 
    return ostr; 
}

Solution 2 - Inlining

loan.h

inline ostream & operator<<(ostream & ostr, Loan & aLoan) { 
    aLoan.printOn(ostr); 
    return ostr; 
}

The second solution will cause the compiler to resolve the function call by inlining the function code at every position in the code where an invocation happens. This causes redundancies in the compiled code and should be avoided for large functions.

Solution 3 - Static

loan.h

static ostream & operator<<(ostream & ostr, Loan & aLoan) { 
    aLoan.printOn(ostr); 
    return ostr; 
}

By declaring the function as static, it has internal linkage. You are still leaving the decision of whether the compiler will inline it or not to the compiler.