c++支持四种编程范式:面向过程、面向对象、模板、函数式编程
#include <iostream>
using namespace std;
int add1(int a,int b){
return a+b;
}
class ADD{
public:
int operator()(int a,int b){
return a+b;
}
}add2;
template<typename T,typename U>
auto add3(T a ,U b) -> decltype(a+b){
return a+b;
}
auto add4 = [](int a,int b) -> decltype(a+b) {return a+b;};
int main(){
ADD add2;
cout << add1(3,4) << endl;
cout << add2(3,4) << endl;
cout << add3(3,4) << endl;
cout << add4(3,4) << endl;
}
预处理、编译与链接
g++ test.cc 这样的命令包含三个过程:
- 预处理生成待编译的源文件,可以通过
g++ -E test.cc -o tmp.cc
单独执行预处理过程,从而查看待编译的源文件 - 编译阶段检查语法错误,生成目标文件(.o),可通过
nm -C test.cc
查看目标文件包含的符号列表 - 链接阶段将声明与定义联系起来,并生成最终的可执行文件
预处理
预处理阶段主要是执行#
开头的预处理命令,如#include
、#define
等,其中#include
就是将头文件复制到源文件中。可以通过g++ -E test.cc -o tmp.cc
单独执行预处理过程,从而查看待编译的源文件例如有以下文件test.cc
#include <cstdio>
using namespace std;
int add(int a, int b);
int sub(int a,int b){
return a-b;
}
int main(){
printf("%d\n",add(3,4));
printf("%d\n",sub(5,3));
return 0;
}
然后执行g++ -E test.cc -o tmp.cc
并查看tmp.cc文件,可以看到tmp.cc文件有接近一千行代码。
条件式编译
条件式编译是在预处理过程中,看条件是否满足来将某个分支的代码选择出来生成待编译的文件,对于不满足条件的分支则不加入待编译的文件。
函数 | 说明 |
---|---|
#ifdef DEBUG | 是否定义了DEBUG 宏 |
#ifndef DEBUG | 是否没有定义了DEBUG 宏 |
#if MAX_N == 4 | 宏MAX_N是否等于4 |
#elif MAX_N == 5 | 否则宏MAX_N是否等于5 |
#else | 否则 |
#endif | 条件式编译必须以它为结尾 |
例如如下示例
#ifdef DEBUG
int op(int a, int b ){
return a+b;
}
#else
int op(int a, int b){
return a-b;
}
#endif
然后可以在编译的时候加入宏定义 -DDEBUG
来控制op
函数使用哪个实现版本。
编译与链接
编译阶段主要是做语法检查,函数的声明主要就是用于编译阶段,函数的定义则作用于链接阶段,定义和声明中一般分别放在头文件和源文件中,以减少重复定义或者未定义的情况。
可以用nm -C test.o
命令查看编译后的符号列表,其中U开头表示的是其定义需要在外文件中找,而T开头表示test.o文件中已经定义。
使用g++进行编译:g++ -c test.cc
,得到test.o
文件后,我们使用nm -C test.o
查看文件中定义的符号列表
xfchen@xfchen-dev:~/workspace/cplusplus$ nm -C test.o
U _GLOBAL_OFFSET_TABLE_
0000000000000016 T main
U printf
U add(int, int)
0000000000000000 T sub(int, int)
可以看到,T开头的是main
和sub
函数,这两个函数在文件中都是有定义的,但是printf
和add
函数都是没有定义的,因此是U开头的,由于编译主要在在做语法检查,因此此阶段不会报错。但是如果想要通过链接阶段,则需要一个包含add
函数定义的.o
文件,例如由add.cc 生成的add.o
,则可以使用g++ test.o add.o
进行链接,如果两个.o
文件出现相同的定义,则在链接时也会报错。
编译链接外部的静态链接库与头文件
假如使用的是googletest编译好的静态链接库lib/libgtest.a
和 头文文件include/gtest/gtest.h
,测试程序代码test.cc如下
#include <gtest/gtest.h>
using namespace std;
int sub(int a,int b){
return a-b;
}
TEST(test,sub){
EXPECT_EQ(sub(4,3),1);
EXPECT_GT(sub(5,3),1);
}
int main(){
return RUN_ALL_TESTS();
}
编译命令:g++ -I./include -L./lib test.cc -lgtest
解析:
-I
参数,添加编译时搜索的路径,这样就能找到<gtest/gtest.h>-L
参数,添加链接时搜索的路径,这样就能找到lib目录下指定的链接库-lgtest
,会自动展开成libgtest
并寻找该文件,这样就能到lib/libgtest.a
googletest 编译时还需要加上-lpthread,以上只是示例