头文件(.h文件)
在编译中向全局符号空间提供符号的原型,例如:函数原型;一般来讲原型的加载优先于所有源文件
源文件(.cpp文件)
头文件提供了接口,让源代码之间的相互调用可以通过符号引用建立关系,但是接口就必须要有实现,也就是编译器在执行期间必须通过符号找到具体的代码这些代码就是写在cpp中,用头文件的同名符号去指定,比如:
函数头文件:
文件名: Demo01-FunctionDemo.h
void printVersion01();
函数源文件:
文件名: Demo01-FunctionDemo.cpp
#include
void printVersion01(){
std::cout << "printVersion1.1;" << std::endl;
}
注意cpp和.h之间建立关系不是通过文件名,而是全局符号空间的符号一致性,例如printVersion01就只会找printVersion01,所以c语言中是比较容易发生符号冲突的,这个时候就需要命名空间的概念我们后续学习
只有.cpp文件才会在代码中建立各个模块的引用关系,因此如果你的.cpp文件需要要用到其他的模块的文件,就必须#include这个头文件
#include "../header/Demo01-FunctionDemo.h"
在h文件中声明的数据的共享的,但是在cpp文件中声明的数据是独立的;
Clion中如何指定多个的main函数?
注意add_executable第一个参数就是我们的测试运行的名字,他会被映射在这里
Clion中右键新增Header
#ifndef和#define以及#endif 都是自动生成的,我们只需要指定头文件的函数原型即可
例子:
#ifndef UNTITLED_DEMO01_FUNCTIONHEADER_H
#define UNTITLED_DEMO01_FUNCTIONHEADER_H
void printVersion01();
void printVersion02();
void printVersion03();
#endif //UNTITLED_DEMO01_FUNCTIONHEADER_H
header:放头文件;
impl:放源文件;
test:放测试文件;
声明函数原型
#ifndef UNTITLED_DEMO01_FUNCTIONHEADER_H
#define UNTITLED_DEMO01_FUNCTIONHEADER_H
void printVersion01();
void printVersion02();
void printVersion03();
#endif //UNTITLED_DEMO01_FUNCTIONHEADER_H
实现函数原型
#include
void printVersion01(){
std::cout << "printVersion1.1;" << std::endl;
}
void printVersion02(){
std::cout << "printVersion1.2;" << std::endl;
}
void printVersion03(){
std::cout << "printVersion1.3;" << std::endl;
}
引入函数原型(Test01.cpp中)
引入函数原型,在编译器期间就可以利用这些符号处理上下文以及各种编译设计,而运行时则利用相同的符号去找到他的实现类
#include "../header/Demo01-FunctionHeader.h"
int main() {
printVersion01();
printVersion02();
printVersion03();
return 0;
}
随意注释一个,函数原型的实现
显示没有当前头文件的引用没有指向任何一个具体的函数
再一次告诉我们,header文件里面函数原型是提供了一个简单的结构引用,这些引用必须要指向具体的代码
新建多个cpp,用同一个符号引用
加入编译
add_executable(
Test01
lessons/lesson01-headerAndCpp/test/Test01.cpp
lessons/lesson01-headerAndCpp/impl/Demo01-FunctionDemo.cpp
lessons/lesson01-headerAndCpp/impl/Demo01-FunctionDemo2.cpp
)
编译报错,符号冲突,由此体现设计命名空间的作用性
修改CMakeList.txt
add_executable(
Test02
lessons/lesson01-headerAndCpp/test/Test01.cpp
)
修改main函数
#include "../impl//Demo01-FunctionDemo.cpp"
int main() {
printVersion01();
printVersion02();
printVersion03();
return 0;
}
结果
事实证明直接include源文件也是直接直接调用的,但是开发过程中源文件的位置以及实现是经常发生变化,这样不太方便维护,因此通过h文件建立关系是非常好可扩展的,类似于java的接口的意义
建立类原型
#ifndef UNTITLED_DEMO02_CLASSDEMO_H
#define UNTITLED_DEMO02_CLASSDEMO_H
class Circle {
/**
* 私有
*/
private:
double r;//半径
public:
Circle();//构造函数
Circle(double R);//构造函数
double Area();//对象函数
};
#endif //UNTITLED_DEMO02_CLASSDEMO_H
实现类原型
如果实现需要用到h里面的命名或者类的空间则需要引入相应的头文件
一般这么写就规范点 而不至于符号冲突
#include "../header/Demo02_ClassDemo.h"
Circle::Circle()
{
this->r=5.0;
}
Circle::Circle( double R)
{
this->r=R;
}
double Circle:: Area()
{
return 3.14*r*r;
}
调用
#include
# include "../header/Demo02_ClassDemo.h"
int main() {
Circle a=Circle(55);
a.Area();
std::cout << a.Area() << std::endl;
return 0;
}
命名空间原型
#ifndef UNTITLED_DEMO02_NAMESPACE01_H
#define UNTITLED_DEMO02_NAMESPACE01_H
namespace print01 {
void print();
}
namespace print02 {
void print();
}
namespace print03 {
void print();
}
#endif //UNTITLED_DEMO02_NAMESPACE02_H
命名空间实现
#include "../header/Demo03_NameSpace01_Function.h"
#include
namespace print01{
void print() {
std::cout << "version01命名空间的输出;" << std::endl;
}
}
namespace print02{
void print() {
std::cout << "version02命名空间的输出;" << std::endl;
}
}
namespace print03{
void print() {
std::cout << "version03命名空间的输出;" << std::endl;
}
}
命名空间调用
#include "../header/Demo03_NameSpace01_Function.h"
int main(){
/**
* 调用方式(一)
* 利用::
*/
print01::print();
print01::print();
print03::print();
/**
* 调用方式(二)
* use
*/
using namespace print01;
print();
/**
* 错误:use 之后的变量名只能用于一个命名空间
*/
// using namespace print01;
// using namespace print02;
// using namespace print03;
// print();
return 0;
}
原型
#ifndef UNTITLED_DEMO02_NAMESPACE02_H
#define UNTITLED_DEMO02_NAMESPACE02_H
namespace version01{
class ConsoleOuter {
public:
ConsoleOuter();
void print();
};
}
namespace version02{
class ConsoleOuter {
public:
ConsoleOuter();
void print();
};
}
namespace version03{
class ConsoleOuter {
public:
ConsoleOuter();
void print();
};
}
#endif //UNTITLED_DEMO02_NAMESPACE02_H
实现
namespace version01{
ConsoleOuter::ConsoleOuter() {
}
void ConsoleOuter::print() {
std::cout << "version01命名空间的输出;" << std::endl;
}
}
namespace version02{
ConsoleOuter::ConsoleOuter() {
}
void ConsoleOuter::print() {
std::cout << "version02命名空间的输出;" << std::endl;
}
}
namespace version03{
ConsoleOuter::ConsoleOuter() {
}
void ConsoleOuter::print() {
std::cout << "version03命名空间的输出;" << std::endl;
}
}
调用
int main(){
/**
* 调用方式 (1)
*/
version01::ConsoleOuter consoleOuter1=version01:: ConsoleOuter();
version02::ConsoleOuter consoleOuter2=version02:: ConsoleOuter();
version03::ConsoleOuter consoleOuter3=version03:: ConsoleOuter();
consoleOuter1.print();
consoleOuter2.print();
consoleOuter3.print();
/**
* 调用方式 (2)
*/
using namespace version01;
ConsoleOuter consoleOuter=ConsoleOuter();
consoleOuter.print();
return 0;
}
调用方式三
在不同代码块内,可以独立使用命名空间
void printVersion01() {
using namespace version01;
ConsoleOuter consoleOuter = ConsoleOuter();
consoleOuter.print();
}
void printVersion02() {
using namespace version02;
ConsoleOuter consoleOuter = ConsoleOuter();
consoleOuter.print();
}
void printVersion03() {
using namespace version03;
ConsoleOuter consoleOuter = ConsoleOuter();
consoleOuter.print();
}
int main() {
printVersion01();
printVersion03();
printVersion02();
return 0;
}