C++类将类的构造器设置为内联的,然后main函数和类的实现不在一个.cpp文件中则会报错

我在测试书上的例子时,按书上把类的构造器前加了inline,main函数和类的实现不在同一个文件中,在测试时报了如下错误:
1>Main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall UserProfile::UserProfile(void)" (??0UserProfile@@QAE@XZ),该符号在函数 _main 中被引用
1>Main.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall UserProfile::UserProfile(class std::basic_string,class std::allocator >,enum UserProfile::uLevel)" (??0UserProfile@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@W4uLevel@0@@Z),该符号在函数 _main 中被引用
1>D:\Visual Studio 2015\Projects\STLStudy\Debug\STLStudy.exe : fatal error LNK1120: 2 个无法解析的外部命令

我把inline去掉或是把main函数放在类的实现的文件中时,就可以正常运行了。想知道为什么。编译器是vs2015

贴出你的代码看下。关键看你的include怎么使用,类怎么定义的。

这是Essential C++上的一个例子,下面是代码

main.cpp

#include"UserProfile.h"
#include

using namespace std;

extern ostream& operator<<(ostream &os, const UserProfile &rhs);
extern istream& operator>>(istream &is, UserProfile &rhs);

int main() {
UserProfile anon;
cout << anon;

UserProfile anon_2;
cout << anon_2;

UserProfile anna("Annal", UserProfile::Guru);
cout << anna;
anna.bump_guess_count(27);
anna.bump_guess_correct(25);
anna.bump_login_count();
cout << anna;

cin >> anon;
cout << anon;

return 0;

}

UserProfile.h

#pragma once
#include
#include

using namespace std;
class UserProfile
{
public:
enum uLevel
{
Beginner,Intermediate,Advanced,Guru
};

UserProfile();
UserProfile(string login,uLevel = Beginner);
~UserProfile();

bool operator==(const UserProfile&);
bool operator!=(const UserProfile &rhs);

//following functions are used to read data
string login()const {
    return _login;
}
string user_name()const {
    return _user_name;
}
int login_count()const {
    return _times_logged;
}
int guess_count()const {
    return _guesses;
}
int guess_correct()const {
    return _correct_guesses;
}
double guess_average()const;
string level()const;

//following functions are used to write data
void reset_login(const string &val) {
    _login = val;
}
void user_name(const string &val) {
    _user_name = val;
}

void reset_level(const string&);
void reset_level(uLevel newlevel) {
    _user_level = newlevel;
}
void reset_login_count(int val) {
    _times_logged = val;
}
void reset_guess_count(int val) {
    _guesses = val;
}
void reset_guess_correct(int val) {
    _correct_guesses = val;
}

void bump_login_count(int cnt = 1) {
    _times_logged += cnt;
}
void bump_guess_count(int cnt = 1) {
    _guesses += cnt;
}
void bump_guess_correct(int cnt = 1) {
    _correct_guesses += cnt;
}

private:
string _login;
string _user_name;

int _times_logged;
int _guesses;
int _correct_guesses;
uLevel _user_level;

static map<string, uLevel> _level_map;
static void init_level_map();

};

UserProfile.cpp
#include"UserProfile.h"
#include

inline UserProfile::UserProfile()
:_login("guest"), _user_level(Beginner),
_times_logged(1), _guesses(0), _correct_guesses(0)
{
static int id = 0;
char buffer[16];

_itoa(id++, buffer, 10);
_login += buffer;

}

inline UserProfile::UserProfile(string login, uLevel level)
:_login(login),_user_level(level),
_times_logged(1),_guesses(0),_correct_guesses(0)
{

}

UserProfile::~UserProfile()
{
}

inline double UserProfile::guess_average() const
{
return _guesses
? double(_correct_guesses) / double(_guesses) * 100
: 0.0;
}

inline bool UserProfile::operator==(const UserProfile &rhs) {
if (_login == rhs._login && _user_name == rhs._user_name) {
return true;
}
return false;
}

inline bool UserProfile::operator!=(const UserProfile &rhs) {
return !(*this == rhs);
}

inline string UserProfile::level()const {
static string _level_table[] = { "Beginner","Intermediate","Advanced","Guru" };
return _level_table[_user_level];
}

ostream& operator<<(ostream &os, const UserProfile &rhs) {
os << rhs.login() << ' '
<< rhs.level() << ' '
<< rhs.login_count() << ' '
<< rhs.guess_count() << ' '
<< rhs.guess_correct() << ' '
<< rhs.guess_average() << endl;
return os;
}

map UserProfile::_level_map;

void UserProfile::init_level_map()
{
_level_map["Beginner"] = Beginner;
_level_map["Intermediate"] = Intermediate;
_level_map["Advanced"] = Advanced;
_level_map["Guru"] = Guru;
}

inline void UserProfile::reset_level(const string &level)
{
map::iterator it;
if (_level_map.empty()) {
init_level_map();
}

_user_level =
    ((it = _level_map.find(level)) != _level_map.end())
    ? it->second : Beginner;

}

istream& operator>>(istream &is, UserProfile &rhs) {
string login, level;
is >> login >> level;

int lcount, gcount, gcorrect;
is >> lcount >> gcount >> gcorrect;
rhs.reset_login(login);
rhs.reset_level(level);

rhs.reset_login_count(lcount);
rhs.reset_guess_count(gcount);
rhs.reset_guess_correct(gcorrect);

return is;

}