CPP代码结构

代码结构

head file

Header files and libraries (Kevin Lynch)
What are header files in C++ ( PROGRAMMING TUTORIAL for beginners)
20211226210828
20211226210857
20211226210915

  • 各组配套的函数都是相互独立的,只有在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

20211226215003
20211226215028

libraries

C++ Libraries For Beginners

20211227001032
但是这样调用Graphics会很花时间,而且别人的Graphics部分可能会有隐私保护(别人不想把实现过程暴露给你),于是生成库文件.dll(常放于bin文件夹)/.lib(常放于lib文件夹)供你调用:
20211226235659
20211226235901
20211226235959
20211227000643
20211227000557
20211227000518
20211227000533
20211226215145
20211226215157
20211227000844

CMakeList.txt

Modern Simple CMake Tutorial

对应文档:Modern Simple CMake Tutorial
关于gtest的使用示例:gtest-cmake-example
其他资料:

  • cmake 和 make
    文件一开始只有main.cpp和CMakeList.txt;用cmake .可以根据CMakeList.txt生成中间文件
    然后用make可以根据中间文件生成可执行文件
    20220115135712
    但是这样有些混乱,所以新建一个build文件夹,在里面进行这些操作:mkdir build -> cmake .. -> make

  • 构建自定义库并链接到可执行文件中(方式1)
    可以构建自己定义的库文件,然后在源文件中调用。目录结构如下:

include/
└── demo1.h
src/
└── demo1.cpp
main.cpp 
CMakeLists.txt

20220115153756
20220115153821
20220115153845
对应的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)
  • 当有多个源文件时

20220115162513
示例:
20220115162655

可行方式1:逐个添加
20220115162919
可行方式2:扫描文件夹,添加多个
20220115163500

  • 调用外部的库(已经通过命令行安装好了)

20220115161346
示例:
20220115161742

  • 调用外部的库(手动安装)
    20220115162026

示例:
20220115162325

cmakelist.txt 工程示例

20220718225133

C和C++的混编

extern “C” In C++

C++中调用C

  • 方式1: 简单方式 - 在.cpp中用extern "C" {} 包裹.c对应的.h头文件
    20220115230642
    在C++中调用C函数,需要在.cpp中include用 extern "C" {}把.c对应的头文件包一下,告诉编译器,那部分用C的规则去调用C函数
    20220115211825
    20220115211839

如果直接混编,则会报错:undefiend reference to …
20220115215150
20220115214931
所以需要把c的头文件包一下,才会正确:
20220115214631

  • 方式2:通用方式 - 直接在.c对应的.h头文件中进行包裹。也是告诉编译器以C语言的命名方式去加载这些符号。
    这样的话,不管是外面的.c还是.cpp调用这个当前.c中的函数,都OK
    20220115230835

    C中调用C++

  • 需要把.cpp对应的.h头文件包用宏包裹一下,告诉编译器这部分C++代码用C的规则编译
    20220115234912
    20220115234956

统一规则

不管是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中的函数
20220115235949

I am in C++ file
======
I am in C file
I am in C++ file
, here, I am called by .c file

20220116000014
20220116000030
20220116000054
20220116000148
20220116000243
20220116000400


   转载规则


《CPP代码结构》 M 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
浮点和定点说明 浮点和定点说明
Fixed PointFixed Point Numbers Floating Point Numbers Fixed Point Binary Fractions
2020-12-26
下一篇 
读“非暴力沟通” 读“非暴力沟通”
视频解读1:读《非暴力沟通》 视频解读2:为什么我们开始拒绝与父母交流? 描述事实 不带主观评价;不要言过其实;一次只说一件事;不要推测对方意图 表达感受和需要 情绪源于自身;第一人称描述(我感到…,因为我…);示弱来解决冲突
2020-11-26
  目录