C/C++ (2. C++入门)

人就是这样子, 自己造囚牢, 关着自己; 自己也做上帝, 自己来崇拜.
生存真实一件可怜的事. --<边城>

第2章 | C++入门

2.1 C++关键字

C++关键字

  • C++98定义了63个关键字
2.1.1 数据类型相关

(1)bool、true、false

  • bool即为布尔类型,属于基本类型中的整数类型,取值为真和假。
  • true和false是具有布尔类型的字面量,为右值,即表示真和假。
  • 字面量:用于表达式源代码中一个固定值的表示法。

(2)char、wchar_t

  • 表示字符型和宽字符型这些整数类型(属于基本类型),但一般只专用于表示字符。char(和signed char、unsigned char一起)事实上定义了字节的大小。char表示单字节字符,wchar_t表示多字节字符。

(3)int、double、float、short、long、signed、unsigned

  • signed和unsigned作为前缀修饰整数类型,分别表示有符号和无符号。
  • signed和unsigned修饰char类型,构成unsigned char和signed char,和char都不是相同的类型;不可修饰wchar_t、char16_t和char32_t。其它整数类型的signed省略或不省略,含义不变。signed或unsigned可单独作为类型,相当于signed int和unsigned int。
  • double和float专用于浮点数,double表示双精度,精度不小于float表示的浮点数。long double则是C++11指定的精度不小于double的浮点数。

(4)explicit

  • 该关键字的作用就是避免自定义类型隐式转换为类类型。

(5)auto

  • auto关键字会根据初始值自动推断变量的数据类型。
2.1.2 语句相关

(1)switch、case、default

  • switch分支语句的起始,根据switch条件跳转到case标号或defalut标记的分支上。

(2)do、for、while

  • 循环语句的组成部分,C和C++都支持这三种循环。

(3)if和else

  • 条件语句的组成部分。if表示条件,之后else表示否定分支。

(4)break、cotinue、goto

  • break用于跳出for、while循环或switch语句。continue用于调到一个循环的起始位置。goto用于无条件跳转到函数内得标号处。一般情况不建议使用goto,风险较大。
2.1.3 定义、初始化相关

(1)const、volatile(易变的,不稳定的)

  • const和volatile是类型修饰符,语法类似,用于变量或函数参数声明,也可以限制非静态成员函数。const表示只读类型(指定类型安全性,保护对象不被意外修改),volatile指定被修饰的对象类型的读操作是副作用(因此读取不能被随便优化合并,适合映射I/O寄存器等)。
  • volatile是“易变的”、“不稳定”的意思。volatile是C的一个较为少用的关键字,它用来解决变量在“共享”环境下容易出现读取错误的问题。
  • volatile 的应用场景:<1>并行设备的硬件寄存器;<2>一个中断子服务程序中访问到的变量;<3>多线程应用中被多个任务共享的变量。

(2)enum

  • 构成枚举类型名的关键字。

(3)export

  • 使用该关键字可实现模板函数的外部调用。对模板类型,可以在头文件中声明模板类和模板函数;在代码文件中,使用关键字export来定义具体的模板类对象和模板函数;然后在其他用户代码文件中,包含声明头文件后,就可以使用该这些对象和函数。

(4)extern

  • 当出现extern “C”时,表示 extern “C”之后的代码按照C语言的规则去编译;当extern修饰变量或函数时,表示其具有外部链接属性,即其既可以在本模块中使用也可以在其他模块中使用。

(5)public、protected、private

  • 这三个都为权限修饰符。public为公有的,访问不受限制;protected为保护的,只能在本类、派生类和友元中访问;private为私有的,只能在本类和友元中访问。
    (6)template
  • 声明一个模板,模板函数,模板类等。模板的特化。

(7)static

  • 可修饰变量(静态全局变量,静态局部变量),也可以修饰函数和类中的成员函数。static修饰的变量的周期为整个函数的生命周期。具有静态生存期的变量,只在函数第一次调用时进行初始化,在没有显示初始化的情况下,系统把他们初始化为0。

(8)struct、class、union

  • 用于类型声明。class是一般的类类型。struct在C++中是特殊的类类型,声明中仅默认隐式的成员和基类访问限定与class不同(struct是public,class是private)。union是联合体类型。满足特定条件类类型——POD struct或POD union可以和C语言中的struct和union对应兼容。
  • 注:POD类型(Plain Old Data),plain—代表普通类型,old—代表可以与C语言兼容。

(9)mutable

  • mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。

  • 10.virtual

  • 声明虚基类,虚函数。虚函数=0时,则为纯虚函数,纯虚函数所在的类称为抽象类。

2.1.4 系统操作I相关

(1)catch、throw、try

  • 用于异常处理。try指定try块的起始,try块后的catch可以捕获异常。异常由throw抛出。throw在函数中还表示动态异常规范。

(2)new、delete

  • new、delete属于操作符,可以被重载。new表示向内存申请一段新的空间,申请失败会抛出异常。new会先调用operator new函数,再在operator new函数里调用malloc函数分配空间,然后再调构造函数。delete不仅会清理资源,还会释放空间。delete先调用析构函数,其次调用operator delete函数,最后在operator delete函数里面调用free函数。malloc申请内存失败会返回空。free只是清理了资源,并没有释放空间。

(3)friend

  • 友元。使其不受访问权限控制的限制。例如,在1个类中,私有变量外部是不能直接访问的。可是假如另外1个类或函数要访问本类的1个私有变量时,可以把这个函数或类声明为本类的友元函数或友元类。这样他们就可以直接访问本类的私有变量。

(4)inline

  • 以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,将所调用的函数代码直接嵌入到主调函数中,没有函数压栈的开销,内联函数提升程序运行的效率。
  • 特性1:inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。
  • 特性2: inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
  • 特性3:inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

(5)operator

  • 和操作符连用,指定一个重载了的操作符函数,比如,operator+。

(6)register

  • 提示编译器尽可能把变量存入到CPU内部寄存器中。

(7)typename

  • typename关键字告诉编译器把一个特殊的名字解释为一个类型。
2.1.5 命名相关

(1)using

  • 在当前文件引入命名空间,例using namespace std;在子类中使用,using声明引入基类成员名称。

(2)namespace

  • C++ 标准程序库中的所有标识符都被定义于一个名为 std 的 namespace 中。命名空间除了系统定义的名字空间之外,还可以自己定义,定义命名空间用关键字 “namespace”,使用命名空间时用符号“::”指定。
  • 使用目的:对标识符的名称进行本地化,以避免命名冲突或名字污染。

(3)typedef

  • typedef声明,为现有数据类型创建一个新的名字。便于程序的阅读和编写。
2.1.6 函数和返回值相关

(1)void

  • 特殊的"空"类型,指定函数无返回值或无参数。

(2)return

  • return表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值,由return后面的参数指定。return通常是必要的,因为函数调用的时候计算结果通常是通过返回值带出的。如果函数执行不需要返回计算结果,也经常需要返回一个状态码来表示函数执行的顺利与否(-1 和 0 就是最常用的状态码),主调函数可以通过返回值判断被调函数的执行情况。

(3)sizeof

  • 返回类型名或表达式具有的类型对应的大小。

(4)typeid

  • typeid是一个操作符,返回结果为标准库中类型的引用。
2.1.7 其他

(1)this

  • 每个类成员函数都隐含了一个this指针,用来指向类本身。this指针一般可以省略。但在赋值运算符重载的时候要显示使用。静态成员函数没有this指针。

(2)asm

  • asm是一个语句的分隔符。不能单独出现,必须接汇编指令。一组被大括号包含的指令或一对空括号。

(3)*_cast(const_cat/dynamic_cast/reinterpret_cast、static_cast)

  • C++类型风格来性转换。const_cast删除const变量的属性,方便赋值;dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或引用;reinterpret_cast将一种类型转换为另一种不同的类型;static_cast用于静态转换,任何转换都可以用它,但他不能用于两个不相关的类型转换。
2.1.8 C、C++ 中0、NULL、nullptr
// C语言表示
#define NULL (void*)0
char* p = NULL;

// C++表示
#define NULL 0
char* p = NULL;
char* p = nullptr;
  • NULL是一个宏定义,在c和c++中的定义不同,c中NULL为(void*)0,而c++中NULL为整数0。
  • nullptr是一个字面值常量,类型为std::nullptr_t,空指针常数可以转换为任意类型的指针类型。
2.2 命名空间
2.2.1 定义
  • (1)在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字 污染,namespace关键字的出现就是针对这种问题的;
  • (2)定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名 空间的成员。
  • (3)普通的命名空间;
  • (4)命名空间可以嵌套;
  • (5)同一个工程中允许存在多个相同名称的命名空间;
  • (6)注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于被该命名空间。
2.2.2 命名空间的使用
  • (1)加命名空间名称以及作用域限定符;
  • (2)使用using将命名空间中的成员引入;
    using N::B;
  • (3)使用using namespace命名空间名称引入;
    using namespace N;
2.3 C++输入&输出
2.3.1 cin&cout
2.3.2 说明
  • (1) 使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间;
  • (2)注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件 即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文 件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用 +std的方式;
    using N::B;
  • (3)使用C++输入输出更方便,不需增加数据格式控制,比如:整形–%d,字符–%c。
    using namespace N;
2.4 缺省参数
2.4.1 缺省参数的定义
  • 缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
2.4.2 缺省参数的分类
  • (1)全缺省参数
    每个参数都带有默认值;
  • (2)半缺省参数
    部分参数带有缺省值。
2.4.3 注意
  • (1) 半缺省参数必须从右往左依次来给出,不能间隔着给 ;
  • (2) 缺省参数不能在函数声明和定义中同时出现;
  • (3)缺省值必须是常量或者全局变量 ;
  • (4) C语言不支持(编译器不支持)。
2.5 函数重载(function overloading)
2.5.1 定义
  • 是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数或类型或顺序)必须不同,即对一个函数名赋予它新的含义,使一个函数名可以多用,也就是“一物多用”,常用来处理实现功能类似数据类型不同的问题;
2.5.2 名字修饰(Name Mangling)
  • (1)Name Mangling是一种在编译过程中,将函数、变量的名称重新改革的机制,简单来说就是编译器为了区分各个函数,将函数通过某种算法,重新修饰为一个全局唯一的名称;
  • (2)C语言的名字修饰规则:非常简答,只是在函数名字前面添加了下划线;
  • (3)C++的名称修饰规则:修饰名字由?开头,接着是函数名由“@”符号结尾的函数名,后面跟着“@”结尾的类名“C”和名称空间“N”,再一个“@”表示函数的名称空间结束,第一个“A”表示函数调用类型为“_cdecl”,接着是函数的参数类型及返回值,由“@”结束,最后由“Z”结尾;
    例如:?func@@YAHH@Z
2.5.3 exetern “C”
  • 有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加exetern“C”,意思是告诉编译器,将该函数按照 C 语言规则来编译;
2.5.4 为什么C语言不支持
  • C语言中编译器对函数名字的修饰规则非常简单:只是在函数名字前增加了一个下划线;
    如果工程中存在同名的函数时,编译器就无法区分调用那个函数;
2.6 auto关键字(C++11)
2.6.1 定义
  • C/C++定义:使用auto修饰的变量,是具有自动存储器的局部变量;
  • C++11中定义:auto不再是一个存储类的指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推到而得;
  • 注意:使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始来推导化表达式auto的实际类型,因为auto并非是一种“类型”的声明,而是一个类型声明的“占位符”,编译器在编译器会将auto替换为变量实际的类型;
2.6.2 auto的使用细则
  • auto与指针和引用结合起来使用。用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型则必须加&;当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量;
2.6.3 auto不能推导的场景
  • (1)auto不能作为函数的参数;
  • (2)auto不能直接用来声明数组;
  • (3) 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法;
  • (4) auto在实际中常见的优势用法就是跟以后会用到的C++11提供的新式for循环,还有lambda表达式等进行配合使用;
  • (5)auto不能定义类的非静态成员变量;
  • (6)实例化模板时不能使用auto作为模板参数。
2.7 基于范围的for循环(C++11)
2.7.1 范围for的语法
  • (1)C++11中 引入了基于范围的for循环,for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围。
  • (2)注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。
2.7.2 范围for的使用条件
  • (1)for循环迭代的范围必须是确定的;对于数组而言,就是数组中第一个元素和后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围;
  • (2)迭代的对象要实现++和==的操作。
2.8 指针空值–nullptr(C++11)
2.8.1 C++98中的指针空值
  • 在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。
2.8.2 nullptr与nullptr_t
  • (1)为了考虑兼容性,C++11并没有消除常量0的二义性,C++11给出了全新的nullptr表示空值指针。C++11为什 么不在NULL的基础上进行扩展,这是因为NULL以前就是一个宏,而且不同的编译器厂商对于NULL的实现可能不太相同,而且直接扩展NULL,可能会影响以前旧的程序;
  • (2)为了避免混淆,C++11提供了 nullptr,即:nullptr代表一个指针空值常量。nullptr是有类型的,其类型为nullptr_t,仅仅可以被隐式转化为指针类型,nullptr_t被定义在头文件中:
    typedef decltype(nullptr) nullptr_t;
2.8.3 注意
  • (1)在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
  • (2) 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  • (3)为了提高代码的健壮性,在后续表示指针空值时建议好使用nullptr。
2.9 引用
2.9.1 定义
  • 引用(reference)是C++对C的一个重要扩充,引用是一个新的变量类型,是给已经存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
2.9.2 引用一般形式
  • 1.通过对象名和成员运算符访问对象中的成员(一般形式:对象名.成员名);
  • 2.通过指向对象的指针访问对象中的成员(例如:p = &t);
  • 3.通过对象的引用变量来访问对象中的成员;类型 & 引用变量名(对象名) = 引用实体(int& ra = a; 定义引用类型);
2.9.3 引用特性
  • 1.引用在定义时必须初始化;
  • 2.一个变量可以有多个引用;
  • 3.引用一旦引用一个实体,再不能引用其他实体。
2.9.4 使用场景

(1)做参数

  • 1.需要通过形参改变外部实参,T&;
  • 2.不需要通过形参改变外部实参,const T&;

(2)做返回值

  • 1.返回全局变量;
  • 2.返回 static 类型的变量;
  • 注意:引用作为函数返回值,一定不能返回函数栈上的空间,即离开函数作用域之后,其栈上的空间已经还给系统,返回结果的生命周期不受函数控制(实体的生命周期闭函数长)。
2.9.5 传值、传址的比较

传值

  • 优点:函数的副作用不会影响外部的实参;
  • 缺点:传参效率低,不能通过形参改变外部的实参。

传址

  • 优点:传参效率高,可以通过形参改变外部实参;
  • 缺点:不安全,可读性差。
2.9.6 引用和指针的区别

相同点

  • 1.在语法概念上引用就是一个别名,没有独立空间,和引用实体共用同一块内存空间;
  • 2.在底层实现上实际是有空间的,因为引用是按照指针方式来实现的;

不同点

  • 1.引用在定义时必须初始化,而指针在定义时没有和这个要求;
  • 2.引用再初始化时引用一个实体后,就不能在引用其他实体,而指针可以任何时候指向任何一个同类型的实体;
  • 3.没有 NULL 引用,但有 NULL 指针;
  • 4.在 sizeof 中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占空间字节个数(32位操作系统下是占4个字节,64位操作系统下是占8个字节);
  • 5.引用自加即引用的实体加1,指针自加即指针向后偏移一个类型的大小;
  • 6.有多级指针,但是没有多级引用;
  • 7.访问实体方式不同,指针需要显示解引用,引用编译器自己处理;
  • 8.引用比指针使用起来相对更安全。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值