代码结构
head file
Header files and libraries (Kevin Lynch)
What are header files in C++ ( PROGRAMMING TUTORIAL for beginners)
- 各组配套的函数都是相互独立的,只有在link后,才生成可执行文件
- 头文件用于声明,源文件用于实现该声明 (两者的文件名甚至可以不对应,为编程规范,文件名应该互相对应)
- 源文件在调用其他文件的函数时,只需要包含相应的头文件即可(在编译时,只需找全它所需要的内容)。编译好后,在运行时,才和.cpp(实现)进行配套
示例:
头文件 Pizza.h:
#ifndef CPP_PIZZA_H
#define CPP_PIZZA_H
#include <string>
void menu(std::string myMenu);
#endif //CPP_PIZZA_H
对应的源文件 MyPizza.cpp:
#include "Pizza.h"
#include <iostream>
#include <string>
void menu(std::string myMenu){
std::cout<<"this is my menu: "<<myMenu<<std::endl;
}
文件demo1.cpp对其进行调用:
#include <iostream>
#include "Pizza.h"
int main(){
std::cout<<"Hello World"<<std::endl;
menu("fruit pizza!");
}
//Hello World
//this is my menu: fruit pizza!
对应的CMakeLists.txt (cpp文件在同一目录下):
cmake_minimum_required(VERSION 3.20)
project(CPP)
set(CMAKE_CXX_STANDARD 14)
add_executable(demo1 demo1.cpp MyPizza.cpp)
注意:虽然可以把
#include <iostream>
写到Pizza.h中,这样源文件MyPizza.cpp和demo1.cpp都可省略#include <iostream>
(因为通过#include "Pizza.h"
也加载了#include <iostream>
),但本着互相独立的原则,尽量不要这样写
理解 C++ 中的头文件和源文件的作用
C++头文件和源文件,编译过程
C/C++ 头文件的作用和用法
- 头文件与库文件的区别
- 在编程过程中,程序代码往往被拆成很多部分,每部分放在一个独立的源文件中,而不是将所有的代码放在一个源文件中。考虑一个简单的小例子:程序中有两个函数main()和abc()。main()函数位于main.cpp,abc()函数位于abc.cpp,main()函数中调用abc()函数。在编译阶段,由于编译是对单个文件进行编译,所以编译main.cpp时,编译器不知道是否存在abc()函数以及abc()调用是否正确,因此需要头文件辅助。运行时,编译器不知道abc的用法是否正确(因为abc在另一个文件abc.cpp中),只有借助头文件中的函数声明来判断。对main.cpp进行编译时,不会涉及abc.cpp文件,只会涉及main.cpp 和abc.h(因为abc.h被include)文件。
- 库文件中包含一系列的子程序。例如abc.cpp 源文件中实现了abc()函数,我们假设abc()函数是包含重要算法的函数,我们需要将abc()函数提供给客户使用,但是不希望客户看到算法源代码。为了达到这一目的,我们可以将abc.cpp编译程库文件,库文件是二进制的,在库文件中是看不到原始的源代码的。库和可执行文件的区别是,库不是独立程序,他们是向其他程序提供服务的代码。 当然使用库文件的好处不仅仅是对源代码进行保密,使用库文件还可以减少重复编译的时间,增强程序的模块化。将库文件连接到程序中,有两种方式,一种是静态连接库,另一种是动态连接库。
Compiling, assembling, and linking
libraries
但是这样调用Graphics会很花时间,而且别人的Graphics部分可能会有隐私保护(别人不想把实现过程暴露给你),于是生成库文件.dll(常放于bin文件夹)/.lib(常放于lib文件夹)供你调用:
CMakeList.txt
Modern Simple CMake Tutorial
对应文档:Modern Simple CMake Tutorial
关于gtest的使用示例:gtest-cmake-example
其他资料:
cmake 和 make
文件一开始只有main.cpp和CMakeList.txt;用cmake .
可以根据CMakeList.txt生成中间文件
然后用make
可以根据中间文件生成可执行文件
但是这样有些混乱,所以新建一个build文件夹,在里面进行这些操作:mkdir build -> cmake .. -> make构建自定义库并链接到可执行文件中(方式1)
可以构建自己定义的库文件,然后在源文件中调用。目录结构如下:
include/
└── demo1.h
src/
└── demo1.cpp
main.cpp
CMakeLists.txt
对应的CMakeList.txt文件为:
cmake_minimum_required(VERSION 3.20)
project(project1)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#通过demo1.cpp构建mylib库
add_library(mylib STATIC src/demo1.cpp)
#这个库文件要包含include文件夹目录中的头文件
target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
# 构建可执行文件
add_executable(hello main.cpp)
#该可执行文件要链接到上面的库文件
target_link_libraries(hello PUBLIC mylib)
- 构建自定义库并链接到可执行文件中(方式2)
可以把自己构建的库文件进一步整合,让外面的CMakeList.txt文件用add_subdirectory(文件夹名)的方式添加库。这时需要在这个子文件夹中添加一个CMakeList.txt文件
MyLibDir
├── CMakeLists.txt
├── include
│ └── demo1.h
└── src
└── demo1.cpp
main.cpp
CMakeLists.txt
MyLibDir文件夹中的CMakeList.txt写为
#通过demo1.cpp构建mylib库
add_library(mylib STATIC src/demo1.cpp)
#这个库文件要包含include文件夹目录中的头文件
target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
外面的CMakeList.txt写为
cmake_minimum_required(VERSION 3.20)
project(project1)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(MyLibDir) # 添加了这个目录
# 构建可执行文件
add_executable(hello main.cpp)
#该可执行文件要链接到上面的库文件
target_link_libraries(hello PUBLIC mylib)
- 当有多个源文件时
示例:
可行方式1:逐个添加
可行方式2:扫描文件夹,添加多个
- 调用外部的库(已经通过命令行安装好了)
示例:
- 调用外部的库(手动安装)
示例:
cmakelist.txt 工程示例
- An Introduction to Modern CMake
- Cmake命令之project介绍:在调用project命令指定当前工程名字的同时,cmake内部会为一些变量赋值
- CMake之install方法的使用
C和C++的混编
C++中调用C
- 方式1: 简单方式 - 在.cpp中用
extern "C" {}
包裹.c对应的.h头文件
在C++中调用C函数,需要在.cpp中include用extern "C" {}
把.c对应的头文件包一下,告诉编译器,那部分用C的规则去调用C函数
如果直接混编,则会报错:undefiend reference to …
所以需要把c的头文件包一下,才会正确:
方式2:通用方式 - 直接在.c对应的.h头文件中进行包裹。也是告诉编译器以C语言的命名方式去加载这些符号。
这样的话,不管是外面的.c还是.cpp调用这个当前.c中的函数,都OKC中调用C++
需要把.cpp对应的.h头文件包用宏包裹一下,告诉编译器这部分C++代码用C的规则编译
统一规则
不管是C中调用C++,还是C++中调用C,为了实现通用性,可以把.c和.cpp对应的.h头文件用下面的宏包裹起来:
example.h
头文件
#ifndef CPP_PIZZA_H
#define CPP_PIZZA_H
#ifdef __cplusplus
extern "C"
{
#endif
void Func(); //
#ifdef __cplusplus
}
#endif
#endif //CPP_PIZZA_H
完整示例:main.cpp中调用demo1.cpp和demo2.c源文件中的函数,其中demo2.c中调用demo1.cpp中的函数
I am in C++ file
======
I am in C file
I am in C++ file
, here, I am called by .c file