源文件根据#include来关联文件
- 系统自带的文件用尖括号括起来,编译器会在系统文件目录下查找
#include <>
- 用户自定义的文件用双括号括起来,编译器首先在用户目录下查找,然后在C++安装目录中查找,最后在系统文件中查找
#include ""
头文件(.h)
- 写类的声明(包括类里面的成员和方法的声明)、函数原型、#define常数等,但一般来说不写出类的具体实现。
- 在写头文件时需要注意,开头和结尾必须按照如下样式加上预编译语句
#ifndef CIRCLE_H
#define CIRCLE_H
// your code
#endif
这样做的目的是防止重复编译。至于CIRCLE_H这个名字实际上是无所谓的,你叫什么都行,只要符合规范都行。原则上来说,非常建议把它写成这种形式,因为比较容易和头文件的名字对应。
源文件(.cpp)
源文件主要写实现头文件中以及声明的那些函数的具体代码,需要注意的是,开头必须#include下实现的头文件,以及要用的的文件
实例
我们使用clion进行开发。
Circle.h文件
#ifndef TUTORIALS2_CIRCLE_H
#define TUTORIALS2_CIRCLE_H
class Circle{
private:
double r;
public:
Circle();
Circle(double R);
double Area();
};
#endif //TUTORIALS2_CIRCLE_H
Circle.cpp文件
#include "Circle.h"
Circle::Circle() {
this->r = 5.0;
}
Circle::Circle(double R) {
this->r = R;
}
double Circle::Area() {
return 3.14*r*r;
}
main.cpp文件
#include <iostream>
#include "Circle.h"
using namespace std;
int main() {
std::cout << "Hello, World!" << std::endl;
Circle c(3);
cout << c.Area() << endl;
return 0;
}
Tips:
-
Circle.h叫做头文件,它是不能被编译的。#include叫做编译预处理指令,可以简单理解成,在Circle.cpp中的#include"Circle.h"指令把Circle.h中的代码在编译前添加到了Circle.cpp的头部。每个.cpp文件会被编译,生成一个.obj文件,然后所有的.obj文件链接起来你的可执行程序就算生成了。
-
至于.h和.cpp具有同样的主文件名的情况呢,对编译器来讲是没有什么意义的,编译器不会去匹配二者的主文件名,相反它很傻,只认#include等语句。但是这样写是一种约定俗成的编程风格**,一个类的名字作为其头文件和源文件的主文件名比如Class1.h和Class1.cpp,这个类的声明在Class1.h中,实现在Class1.cpp中,我们人类看起来比较整齐,读起来方便,也很有利于模块化和源代码的重用**
-
因为C++模板类中的处理方法不一样,因为需要传入参数才能确定内存如何分配,所以编译完成时并没有解决所有问题。如果使用常规的处理方法,即.h中是类的声明,.cpp中是类的实现,然后在main.cpp中#include .h文件会报“undefined reference to”的错误。有三种解决办法:
- 解决方法一,在main.cpp中#include “xxxx.cpp”,而非"xxxx.h",这种方式就如同将队列类的声明实现放在同一文件中。
- 解决方法二,在xxxx.h中,代码部分结尾处#include “xxxx.cpp”,并且去掉xxxx.cpp里的包含语句,这与上述方式如出一辄,只是在main.cpp中看上去就像习惯中的方案一样。
- 解决方法三,声明类时,在类名前加上export关键字,抱歉如今的c++编译器中这关键字多半行不通。就像foreach之类的关键字一样,多半会被认为是关键字,但是却是编译器不认识的。