为什么内联我的访问器会破坏我的代码?

Why does inlining my accessors break my code?

我遇到了一个奇怪的问题,即尝试 inline 我的 "Person" class 的访问器导致代码无法编译。

以下代码将编译并 运行 成功(使用 Visual Studio 2012):

Person.h

#pragma once
#include <string>

using namespace std;

class Person
{
public:
    Person(string name, int age = 0);
    ~Person(void);

    // Accessors
    string name(void) const;
    int    age (void) const;

private:
    string m_name;
    int    m_age;
};

Person.cpp

#include "stdafx.h"
#include "Person.h"


Person::Person(string name, int age) :
    m_name(name),
    m_age (age )
{}


Person::~Person(void) {}

string Person::name(void) const
{
    return m_name;
}

int Person::age(void) const
{
    return m_age;
}

header_test.cpp

#include "stdafx.h"
#include <iostream>
#include "Person.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    Person p("Joe");

    cout << p.name() << endl;

    return 0;
}

如果我将访问器更改为定义为 inline 函数代码中断。

在 Person.h

中内联访问器
// Accessors
inline string name(void) const;
inline int    age (void) const;

在 Person.cpp

中内联访问器
inline string Person::name(void) const
{
    return m_name;
}

inline int Person::age(void) const
{
    return m_age;
}

这样做会产生以下错误:

1>header_test.obj : error LNK2019: unresolved external symbol "public: class std::basic_string,class std::allocator > __thiscall Person::name(void)const " (?name@Person@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function _wmain

1>fatal error LNK1120: 1 unresolved externals

上帝啊,那个错误信息是神秘的...谢谢你提供的所有这些非常有用的信息 Microsoft/Visual Studio!


我知道 inline 关键字对编译器来说只是一个 "hint",在这里可能没有实际价值,但它仍然不应该破坏代码!

为什么会这样?

我不是语言律师,所以我无法判断编译器行为是否合法。然而,我可以解释发生了什么。

当您标记函数 inline 时,您 不是 暗示编译器它可以内联此函数。由于 10 多年以来,编译器在这里不需要您的提示。他们知道什么时候内联。相反,您所做的是将函数定义指示为包含在其中的每个翻译单元的本地函数定义。对于此定义应该可用。

实际上您所说的是 name() 定义对于每个 .cpp 文件都应该是本地的,但是您并没有让它对每个 .cpp 文件都可用!我仍然相信编译器会在这里发出警告。

如果要使用inline关键字,需要在header中定义函数body。 inline 不仅仅是给编译器一个提示:它或多或少地关闭了 "one definition" 关于函数被定义一次且仅一次的规则*。

此外,如果在 header 中定义 class 成员函数,ala

class Foo {
    int bar() { return 5; }
};

他们默认得到 "inlined",所以没有理由输入关键字:-)

* 从技术上讲不是,但为简单起见,您可以将其视为那样。请参阅下面 SergeyA 的评论。