阅读本文之前,可先参考c 语言核心
c++相对于 c 语言,主要是增加了面向对象和模板编程
c++中的实体 C++ 程序中的实体包括:值、对象、引用、 结构化绑定 (C++17 起)、函数、枚举项、类型、类成员、模板、模板特化、命名空间和形参包。预处理器宏不是 C++ 实体。
对象类型:非函数类型、非引用类型且非 void 类型的 所以,以下实体都不是对象:值,引用,函数,枚举项,类型,类的非静态成员,位域,模板,类或函数模板的特化,命名空间,形参包,和 this。
名字查找和命名空间 作用域:文件作用域(全局作用域)、命名空间作用域、类作用域、块作用域、枚举作用域、函数作用域、函数形参作用域、模板形参作用域
内部链接和外部链接 内部链接:其他编译单元无法访问的名称,拥有内部链接,相反是外部链接
以下为内部链接:
所有声明
类型(struct/union/enum 等)
命名空间中的 static 函数和变量以及 const 常量
inline 函数
以下为外部链接:
命名空间中的非 static 函数和变量
类成员函数(包含成员函数和 static 成员函数)和静态成员变量
类型比较 c++有如下类型:
基本类型
void
nullptr:空指针
算术类型
整数类型
bool 类型
字符类型
窄字符:(char、signed char、unsigned char、char8_t)
宽字符:(char16_t、char32_t、wchar_t)
整数类型:各种限定的 int
浮点类型:(float 、 double 、 long double)
复合类型
数组类型
函数类型
指针类型(包括对象指针,函数指针,成员函数指针,数据成员指针)
引用类型
枚举类型
类类型
联合体类型
基本类型异同 空指针字面量
为什么需要空指针字面量? 空指针用于表示一个无效的指针,它的值为 0(早期 C 语言的实现中可能有非 0 空指针,现在已经不用)。对指针置 NULL 即标记指针无效,避免“野指针”的恶果
c 语言空指针定义于<stddef.h>,它可以被定义为 ((void*)0), 0 或 0L,这取决于编译器供应商。
1 2 3 4 5 6 7 #define NULL 0 #define NULL ((void*)0) int * p = malloc (10 * sizeof (int )); void *pv = p;
c++中空指针定义如下:
1 2 3 #define NULL 0 #define NULL nullptr
问题一:为什么 c++把 NULL 定义为 0,而不是 void? 因为 c++中不允许(void )到其他类型指针的隐式类型转换
1 2 3 4 #define NULL ((void*)0) int * a = NULL ; int * a = (int *)NULL ; int * a = 0 ;
结论:c++中,NULL 只能被定义为 0
问题二:有了 NULL 表示空指针,c++11 为什么增加 nullptr_t ? 当 NULL 被定义为 0 后,在函数重载时,会发生歧义,如下
1 2 3 4 5 6 7 8 void Func (char *) ;void Func (int ) ;int main () { Func(NULL ); Func(nullptr ); }
c++11 的解决方案,定义个 std::nullptr_t 类型,该类型定义了转到任意指针类型的转换操作符,同时不允许该类型的对象转换到非指针类型
结论:用 nullptr 类型表示无效指针后,既不需要初始化时显示转换的麻烦,又避免 NULL 定义为 0 时的函数重载问题,而保留 NULL 只是为了向后兼容。所以 c 中使用 NULL,c++11 中使用 nullptr。
bool 类型 c99 开始,增加关键字_Bool 支持布尔类型
1 2 3 #define bool _Bool #define true 1 #define false 0
c99 后,bool,true,false 为宏定义,在<stdbool.h>中 c++中,bool,true,false 均为关键字
字符类型
c++中,目前有以下内置字符类型(关键字): char char8_t (C++20 起):UTF-8 字符表示的类型,char8_t utf8[] = u8”我” char16_t (C++11 起):UTF-16 字符表示的类型,char16_t utf16[] = u”我” char32_t (C++11 起):UTF-32 字符表示的类型,char32_t utf32[] = U”我” wchar_t: 实现定义,windows 为 16 位 short 类型,gcc 为 32 位 int 类型,定宽字符
c 语言中,使用宏定义实现:
1 2 3 typedef unsigned short wchar_t ; typedef uint_least16_t char16_t ; typedef uint_least32_t char32_t ;
字符串使用原则: 程序内部使用 char8_t(UTF-8 编码)字符串,既可以表示所有字符,又不浪费空间 求字符串长度等操作时,转换为 wchar_t 宽字符串方便操作,char16_t 和 char32_t 存在字节序问题,不建议使用 注意:宽字符和窄字符相互转换,或者输出到控制台时,需要设定正确的 locale,才能正确解析窄字符串
引用类型 c++增加引用类型,表示一个标识符的别名,故不占用存储空间 没有数组的引用,没有指针的引用,没有引用的引用
面向对象 通过 class 或者 struct 支持面向对象编程
编译器默认会定义的成员函数:
1 2 3 4 5 6 7 8 class A { A() {} A( const A & ) {} }
c++中的多态: 函数重载:可以定义不同参数的相同名称的函数,编译期,原理是编译器会产生不同的符号 多态:基类中定义的虚函数,可以被子类覆盖,运行时调用不同的函数 多态原理:通过虚函数表和虚表指针实现,编译器为每个定义了虚函数的类分配一个虚函数表,表中存放的是这个类所有虚函数的指针,每个类对象的最前面存放的是虚函数表指针,
模板编程 通过模板编程支持范型编程,让程序员编写与类型无关的通用代码,比如通用算法
1 2 3 4 5 6 template <class 形参名, class 形参名, ...> 返回类型 函数名(参数列表) { ... }template <class 形参名, class 形参名, ...> class 类名{ ... };}
模板有显式实例化,隐式实例化,特化(具体化) 隐式实例化:运行期间,根据参数动态生成模板实例 显式实例化:编译期间,生成对应的实例 特化:针对自定义参数,不能生成对应实例时,跟显示实例化一样,编写针对特定类型的模板