问题描述:
在C++ Primer Chapter 7中作为例子,定义了Screen类,并且在其中使用了内联的成员函数,由于书为英文版,我对内联函数的声明和定义的位置理解出现偏差,把声明写在的头文件中,而把定义写在了cpp文件中。在编译时,VS2013产生了LINK2019的链接错误。
源代码如下:
//Screen.h
class Screen
{
public:
using pos = std::string::size_type;
Screen() = default;
Screen(pos ht, pos wd, char c = ' ') :
height(ht), width(wd), contents(ht*wd, c){};
char get() const
{ return contents[cursor]; };
inline char get(pos ht, pos wd) const;
inline Screen &move(pos r, pos c);
inline Screen &set(char c);
inline Screen &set(pos, pos, char);
Screen &display(std::ostream &os)
{
do_display(os); return *this;
}
const Screen &display(std::ostream &os) const
{
do_display(os); return *this;
}
private:
void do_display(std::ostream &os) const
{
os << contents;
};
pos cursor = 0;
pos height = 0, width = 0;
std::string contents;
};
//Screen.cpp
char Screen::get(pos ht, pos wd) const
{
return contents[ht*width + wd];
}
Screen &Screen::move(pos r, pos c)
{
cursor = r*width + c;
return *this;
}
Screen &Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
Screen &Screen::set(pos row, pos col, char c)
{
contents[row*width + col] = c;
return *this;
}
//main.cpp
int main() //VS2013: LINK 2019
{
Screen sc(5, 5, 'X');
sc.move(4, 0).set('#').display(std::cout);
std::cout << "\n";
sc.display(std::cout);
std::cout << "\n";
return 0;
}
根据C++ Primer 6.5.2 P.240的描述,inline函数虽然可以在程序中定义多次,但是所有的定义必须要精确匹配,所以inline函数通常定义在头文件中。
MSDN对于LINK 2019错误给出了一个函数内联问题的参考文献,其中指出:
如果要使用函数内联必须:
1. 在包括的头文件中实现内联函数
2. 在头文件中打开内联
如果使用 #pragma inline_depth 编译器指令,请确保设置了大于或等于 2 的值。 值为零将关闭内联。 同时确保使用 /Ob1 或 /Ob2 编译器选项。
在不同模块上混合内联和非内联编译选项有时会导致问题。 如果创建 C++ 库时打开了函数内联(/Ob1 或 /Ob2),但描述函数的相应头文件的内联是关闭的(没有选项),将得到错误 LNK2001。 函数不从头文件内联到代码中,但由于它们不在库文件中,因此没有解析引用的地址。
同样,如果项目使用函数内联,但在 .cpp 文件(而非头文件)中定义函数,也会得到 LNK2019。 头文件包含在任何被认为合适的位置,但只有在 .cpp 文件通过编译器时函数才内联;因此当函数用于其他模块时,链接器将函数看成无法解析的外部对象。
参考:MSDN:函数内联问题
解决方法是将类内联成员函数声明与其定义放在对应类的头文件中。
//Screen.h
class Screen
{
public:
using pos = std::string::size_type;
Screen() = default;
Screen(pos ht, pos wd, char c = ' ') :
height(ht), width(wd), contents(ht*wd, c){};
char get() const
{ return contents[cursor]; };
inline char get(pos ht, pos wd) const; //Declaration of an inline function
inline Screen &move(pos r, pos c);
inline Screen &set(char c);
inline Screen &set(pos, pos, char);
Screen &display(std::ostream &os)
{
do_display(os); return *this;
}
const Screen &display(std::ostream &os) const
{
do_display(os); return *this;
}
private:
void do_display(std::ostream &os) const
{
os << contents;
};
pos cursor = 0;
pos height = 0, width = 0;
std::string contents;
};
//Definition of inline funtion
//Put it in corresponding header file
char Screen::get(pos ht, pos wd) const
{
return contents[ht*width + wd];
}
Screen &Screen::move(pos r, pos c)
{
cursor = r*width + c;
return *this;
}
Screen &Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
Screen &Screen::set(pos row, pos col, char c)
{
contents[row*width + col] = c;
return *this;
}
本文探讨了C++内联函数的正确使用方法,解决了因内联函数定义位置不当导致的编译错误问题。通过调整Screen类成员函数的声明与定义位置,确保内联函数在头文件中定义,避免了链接错误。


被折叠的 条评论
为什么被折叠?



