C++语言

本文详细介绍了C++语言中的头文件引入方式、预处理器的宏定义、标识符拼接和pragma,以及关键字的使用,包括new/delete、模板、typedef/using、decltype/auto等。此外,还探讨了预处理器的条件编译和防御式申明,以及头文件的搜索顺序。通过对C++的关键字和预处理器的深入理解,有助于提高编程效率和代码质量。
摘要由CSDN通过智能技术生成

0. 课程目标

学多深?以被面试官问到的深度为参考。

按照cppreference中对c++知识的梳理,本材料依照下图中的树形结构分门别类记录知识点。
在这里插入图片描述
其中黄框内的特性是c++11起支持的,将在这个博客中单独呈现;
其中容器库内容很多,将在这个博客中单独呈现;

所以本博客主要学习语言和头文件部分;
头文件的内容很少,不单独做大标题,放在基本概念中;
本文仅包含下列内容:
在这里插入图片描述

1. 头文件

c++中头文件引入方式是尖括号不带后缀,例如: 等等,因为系统头文件也会互相引用,因此不必include全,一般用clion等IDE也会自动提示。

对于一些形式为 xxx.h 的 C 标准库头文件,C++ 标准库同时包含同名的头文件和拥有形式 cxxx 的头文件。

尖括号or双引号?

  • 使用 “xxx.h”,告诉编译器,从当前工作目录开始查找;
  • 使用<xxx.h>,告诉编译器,从系统默认目录中去查找;
  • 若 #include “” 查找成功,则遮蔽 #include <> 所能找到的同名文件;

搜索顺序?

  • 当前目录
  • -I指定的目录
  • gcc的环境变量CPLUS_INCLUDE_PATH(C程序使用的是C_INCLUDE_PATH)
  • gcc的内定目录:/usr/include,/usr/local/include,/usr/lib/gcc/x86_64-redhat-linux/4.1.1/include

用户头文件的编写要注意防御式申明,防止头文件反复引用,官方的称呼是“Conditional inclusion”。

// xx.h
#ifndef __SOMETHING__
#define __SOMETHING__
...
#endif

2. 预处理器

预处理器在编译前的翻译阶段执行。

  • 有条件编译源文件的某些部分(由 #if、#ifdef、#ifndef、#else、#elif 和 #endif 指令控制); 编译开关
  • 替换文本宏,同时可能对标识符进行拼接或加引号(由 #define 和 #undef 指令与 # 和 ## 运算符控制); 函数工厂
  • 包含其他文件(由 #include 指令控制);
  • 由实现定义的行为(由 #pragma 指令控制);

2.1 define宏

#define 标识符 替换列表(可选) (1)
#define 标识符( 形参, … ) 替换列表(可选) (C++11 起) (2)
(1)仿对象宏,注意#define只是简单机械的替换,注意展开后的语义,尽量加括号保护
(2)仿函数宏,以标识符中的括号为特征

2.2 标识符拼接

字符串化
仿函数宏中,如果替换列表 中一个标识符前有 # 运算符,则该标识符在运行形参替换的基础上以引号包围,实际上创建一个字符串字面量。另外,预处理器为内嵌的字符串字面量(若它存在)外围的引号添加反斜杠以进行转义,并按需要双写字符串中的反斜杠。移除所有前导和尾随空白符,并将文本中间(除内嵌字符串字面量中间外)的任何空白符序列缩减成单个空格。此操作被称为“字符串化”。

另外,#@表示加单引号;

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // 展开成 puts("")
showlist(1, "x", int); // 展开成 puts("1, \"x\", int")

标识符拼接
如果 替换列表 中任何两个相继标识符之间有 ## 运算符,则这两个个标识符(首先未被宏展开)在运行形参替换的基础上将结果进行拼接。此操作被称为“拼接”或“记号粘贴”。

// 制造函数工厂并使用它
#define FUNCTION(name, a) int fun_##name() { return a;}

2.3 pragma

优点:头文件标准防护中,必须保重宏名唯一,#pragma once使得错误地在多个文件中使用相同的宏名变得不可能。
缺点:#pragma once 的文件是基于其文件系统层次的身份所排除的,所以若头文件在项目中有多个位置,则这不能防止包含它两次。

3. 关键字

3.1 new/delete

c中malloc()、freee()是函数,分配堆内存;
c++中new、delete是操作符;分别进行2步操作:
1.内存的分配,2.构造函数的调用;
3.析构函数的调用,4.内存的销毁。

void* operator new(size_t size);
void* operator new[](size_t size);
void  operator delete(void *p);
void  operator delete[](void *p);

简言之,new和delete不仅承载着内存分配的功能还承载着对象构造/析构函数的调用功能。
new和delete对内存分配的功能实际上还是由调用malloc()/free()实现。

c++中delete和delete[]要注意甄别,申请内存数组时,new type[num]会记住申请了几个对象,delete[]会据此多次调用析构函数。举个栗子

3.2 template/typename/typedef/using

template
模板是==泛型编程==的基础,例如我们常使用的vector a;就是用int类型实例化类模板。

常见用法:函数模板、类模板;

template<class T>
template<typename T>

两者没有本质区别,早期没有typename关键字,现在更推荐用typename
T只是占位符,用其他名称代替也行。

类模板,即class中有些数据类型用T指代:

template<typename T>
class A {
   
public:
	A(T r = 0) : re(r) {
   }
private:
	T re;
	...
};
A<double> a1(0.4);

函数模板,编译器会自动进行实参推导(argument deduction);

stone r1(2,3), r2(3,4), r3;
r3 = min(r1, r2);
template<class T>
inline const T& min(const T&am
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值