LINK 2019 inline函数问题

本文探讨了C++内联函数的正确使用方法,解决了因内联函数定义位置不当导致的编译错误问题。通过调整Screen类成员函数的声明与定义位置,确保内联函数在头文件中定义,避免了链接错误。

问题描述:

在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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值