1.头文件不直接参与编译,而参与预编译,当头文件被include时才被编译使用。因此vs的c++工程中有一个默认的stdafx.cpp,里面只有一行#include "stdafx.h",用于确保预编译它。
2.这个#include "stdafx.h" 没有分号,不是语句而是相当于宏定义(#define、#ifndef等),多数情况可以当作把头文件中的内容复制到该位置。因此不要把变量和函数定义在头文件,否则有两个或以上cpp使用头文件时,变量就在各个cpp都定义而造成重定义。有例外:该头文件只被一个cpp文件使用,因此只会在该cpp中定义一次,但这样干嘛不写到cpp中,只为一个cpp服务的头文件有什么用。
3.vs中,如果设置里没搞其他预编译设置,则任意cpp(.h不用)文件开头第一句必须是#include "stdafx.h"
。不写则报错:是否忘记添加stdafx.h,不在第一句则报其他未定义错误。
4.内联函数:在调用时进行代码替换,但实际上是否进行代码替换由编译器决定。有需要(如模板函数)可以在头文件中定义内联函数。可右转另一篇文章:https://www.jianshu.com/p/ba4054d58d41
5.对于类的几点:
(1)非模板类的成员函数可以分开定义在cpp中,但模板类则必须都在一个头文件中否则报各种link error。
(2)在类内部定义的成员函数是内联函数。
(3)多个cpp都要用的类,请定义在头文件中(在cpp中定义class A,在头文件声明class A;
这样行不通,cpp无法了解该类的结构组织)。
(4)与在头文件中定义函数和变量不同,在头文件中定义类不会在其他cpp include的时候造成重定义。
原因也可以简单提下:
与java万物皆是对象不同,class A
的A并不是一个对象也不是变量名,只是像结构体一样的结构信息,在编译时提供信息,因此两个cpp中class A{}
不会造成链接时变量重定义。但在一个cpp中就会有类型重定义错误,因为编译时只需一份结构信息来编译。
6.对于命名空间的变量,也会如同变量和函数在头文件中出现的重定义问题。命名空间虽然无法声明,但多处定义的命名空间会自动合并,因此要这样:
//A.cpp
namespace A
{
int a;
}
//A.h
namespace A
{
extern int a;
}
头文件的命名空间的变量使用extern以作声明即可。重定义问题跟不在命名空间的普通变量一样的规则。
总而言之:
1.普通函数、变量不要在头文件定义。采用头文件声明,cpp中定义的做法。内联函数可直接定义在头文件中。
2.对普通类:在头文件中定义类、声明成员函数(或在类内里定义、采用内联函数定义)。在cpp中定义成员函数。
对模板类:全部定义放在头文件中。
3.对命名空间:如上示例。
4.编译器把头文件的声明与cpp的定义自动对应起来,不需要其他操作。
5.#pragma once、#ifndef这些可以解决:A.h包含B.h、B.h包含A.h的相互包含问题,在对#include复制替换时不会陷入死循环。但不能解决上面所述的重复定义问题。