对于const常量定义在头文件的思考

今天在看effective C++ title02 时,看到一句话:由于常量定义式通常被放在头文件中(以便被不同的源码含入)。感觉十分困惑,因为在我的印象中,变量是不能定义在头文件中的,会引起重复定义的错误。


c++primer原文:   默认状态下,const对象仅在文件中有效

当以编译时初始化的方式定义一个const对象时,就如对bufSize的定义一样:

const int bufSize = 512:

为了执行上述替换,编译器必须知道变量的初始值。如果程序包含多个文件,则每个用了const对象的文件都必须得能访问到它的初始值才行。要做到这一点,就必须在每一个用到变量的文件中都有对它的定义。为了支持这一用法,同时避免对同一变量的重复定义,默认情况下,const对象被设定为仅在文件内有效。当多个文件中出现同名的const变量时,其实等同于在不同文件中分别定义了独立的变量。(注意是等同于 分别 定义了 一份)

某些时候有这样一种const变量,它的初始值不是一个常量表达式,但又确实有必要在文件间共享。这种情况下,我们不希望编译器为每个文件分别生成独立的变量。相反,我们想让这类const对象像其他(非常量)对象一样工作,也就是说,只在一个文件中定义const,而在其他文件中声明并使用它。


解决的办法是,对于const变量不管是声明还是定义都添加extern关键字,这样只需定义一次就可以了

file.cpp:

extern const int bufSize = fcn();

file.h:

extern const int bufSize;


Note:如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字


相似的,static变量也是仅在文件中有效

但是extern跟static是不允许同时出现的






******************************************************************************************************************************************************


其实不光是变量的定义不能出现在头文件中(当然除了上面讲的作用域为本文件的外),函数的定义也是不能出现在头文件中的

如:


vectortest.h
#ifndef  __VECTORTEST_H__
#define  __VECTORTEST_H__

#include <iostream>
#include <vector>
#include <stdint.h>

class Base
{
public:
	typedef std::vector<int32_t> VecInt;
	typedef std::vector<int32_t>::iterator VecIntIt;

	void testVector();
		/*{
	VecInt a;
	a.push_back(1);
	a.push_back(2);
	for (VecIntIt it = a.begin(); it != a.end(); ++it)
	{
	std::cout << *it << std::endl;
	}
	}*/
};


void Base::testVector()
{
	VecInt a;
	a.push_back(1);
	a.push_back(2);
	for (VecIntIt it = a.begin(); it != a.end(); ++it)
	{
		std::cout << *it << std::endl;
	}
}


#endif



listtest.h

#ifndef __LIST_H__
#define __LIST_H__

#include "vectortest.h"

void testList();
#endif

listtest.cpp

#include "listtest.h"

void testList()
{
	Base a;
	a.testVector();
}


main.cpp

#include <iostream>
using namespace std;
#include <stdint.h>
#include "vectortest.h"
#include "listtest.h"

int32_t main()
{
	Base a;

	a.testVector();

	testList();


	system("pause");
	return 0;
}


这是VS报的错

1>main.obj : error LNK2005: "public: void __thiscall Base::testVector(void)" (?testVector@Base@@QAEXXZ) 已经在 listtest.obj 中定义
1>D:\VS2013_Solution\STL_test\Debug\STL_test.exe : fatal error LNK1169: 找到一个或多个多重定义的符号

(这里的例子举的并不好,因为其实是类的成员函数重复定义了,其实我写的第一个例子是关于函数的,只要把Base类去掉,单独留下函数就行。我写类是看看类的函数定义能不能在头文件,当然肯定是不能的了)

这样编译会报一个链接错误,因为在 listtest.h 中包含了 vectortest.h的头文件,而且函数的定义是写在头文件中的,函数默认就是extern的,那么就会引起重复定义,链接报错




其实只要记住,不管是变量还是函数,都将声明放在头文件,定义放在cpp文件,那么就肯定不会搞错了




和其他函数不一样,内联函数和constexpr函数可以在程序中多次定义。毕竟,编译器要想展开函数仅有函数声明是不够的,还需要函数的定义。不过,对于某个给定的内联函数或者constexpr函数来说,它的多个定义必须完全一致。基于这个原因,内联函数和constexpr函数通常定义在头文件中。




猜你喜欢

转载自blog.csdn.net/angel69devil/article/details/76557066
今日推荐