目录

1.前言
2.C++关键字
3.命名空间
    3.1.命名空间的定义
    3.2.命名空间的使用
4.C++的输入和输出
5.缺省参数
    5.1.缺省参数的概念
    5.2.缺省参数的分类
    5.3.缺省参数的注意点
6.函数重载
    6.1.函数重载的概念
    6.2.函数重载的注意点
    6.3.为什么C++支持函数重载------名字修饰
    6.4.小结
7.extern “C”
8.引用
    8.1.引用的概念
    8.2.引用的特性
    8.3.常引用
    8.4.引用做参数
    8.5.引用做返回值
9.内联函数
    9.1.概念
    9.2.特性
10.auto关键字(C++11)
11.范围for
12.nullptr

1.前言

本文主要对于C++的一些特性进行简单介绍,旨在对于C++基于C语言添加的功能及特性进行快速入门

2.C++关键字

相比于C语言的32个关键字,C++的关键字加至63个,很大程度上拓展了C语言的功能。

3.命名空间

在C/C++中,变量,函数和类都是大量存在的。这些变量,函数,类都存在于全局作用域中,可能导致很多冲突。举个例子,我们的命名的变量跟库里的变量名,函数名冲突了。就会导致重命名的问题。在实际大型项目的开发中,还存在同事之间定义的变量/函数/类型命名冲突的情况。

比如说,在头文件<stdlib.h>中包含了一个计算两数较大值的宏max,而我不知道<stdlib.h>里面包含了这个宏,我又恰好引用了<stdlib.h>,同时写了一个名为max的函数。悲催的一幕发生了,编译器始终提示我定义函数max的那一行有重命名的错误,我却死活搞不懂到底怎么回事。。。。。。

为了对标识符的名称进行本地化,以避免命名冲突和名字污染,namespace便应运而生了。

3.1.命名空间的定义

我们刚刚提到C++有63个关键字,几乎比C语言多了一倍。那么,我们就来看看其中新增的一个关键字——namespace吧!

定义命名空间,我们就需要用到namespace关键字,后面跟命名空间的名字。然后接一对{}即可。{}中包含的即为命名空间的成员。

比如说,我和小许合作开发一款社交软件,我们都在自己的文件里定义了全局变量cq。那在链接的过程中,就会报重命名的错误。于是,我们只好采用不同的命名空间来定义我们各自的cq变量啦!

我们在全局定义了命名空间C1和C2:

namespace C1 {int cq = 30;
}
namespace C2 {int cq = 80;
}

不仅如此,我们还可以在命名空间里定义其他任意类型的变量以及函数:

namespace n1 {char ch;int a;double b;struct book{char name[20];int price;int number;};int Add(int x, int y){return x + y;}
}

甚至还可以嵌套定义命名空间:

namespace n2
{int a;int b;namespace n3{int Sub(int x, int y){return x - y;}}
}

最后,同一个工程中允许存在多个相同名称的命名空间,编译器会最后合成到同一个命名空间中。

namespace C1 {int cq = 30;
}
namespace C1 {int cp = 40;
}

好了,我们定义了各自的命名空间里定义了各自的cq,那用的时候怎么引用cq变量呢?

3.2.命名空间的使用

今有命名空间N

namespace N {int a = 30;int b = 40;int c = 50;
}

我们有三种方法来使用命名空间N中定义的变量

  • 使用 using namespace 直接将命名空间中的变量全部展开到全局
using namespace N;

优点:无脑方便
缺点:把定义的变量暴露出去了,容易造成命名污染

  • 使用命名空间名称+域操作符 :: 在访问时指定命名空间
cout << N::rand <<endl;

优点:不存在命名污染
缺点:用起来太烦了

  • 使用 using 将部分命名空间成员展开
using N::a;
using N::b;

这样既降低了命名污染的概率,又能在使用变量时偷懒了

4.C++的输入和输出

初识一门新语言,我们按老规矩办事!

#include <iostream>
using namespace std;
int main()
{cout << "hello world!" << endl;return 0;
}

于是,hello world!便打印在了控制台中了!
我们来认识一下C++的输入输出运算符

  • >> 是输入运算符/流提取运算符
cin >> n;
  • << 是输出运算符/流插入运算符
cout << a[i];

注意:

  1. 我们应当注意尖括号的方向!
  2. 使用cout标准输出(控制台)和cin标准输入(键盘)的时候,必须包含< iostream >头文件以及std标准命名空间。
  3. 使用C++输入输出更方便,不需增加数据格式控制,比如:整形–%d,字符–%c
  4. cout可以连续输出,endl表示换行
cout<< "hello" << " " << "world" << "!" << endl;

5.缺省参数

备胎,就是给汽车准备一个备用轮胎,一旦那个轮子爆胎或者出了问题,备用轮胎就方便及时地取而代之,汽车就不至于中途抛锚。

顾名思义,这“感情备胎”就是给自己在感情的归宿上像轮胎一样,有多一个甚至多个备份,“感情备胎”一般多指爱情。

悄悄告诉你,C++的函数参数也有备胎哦!

5.1.缺省参数的概念

缺省参数是指在声明或定义函数时给函数的参数指定一个默认值

在调用该函数时,如果没有指定实参,就采用这个默认值,否则就采用实参。

比如说,我们希望malloc/realloc有默认开辟的大小。在希望使用默认值的时候缺省参数,不希望的时候传一个自己想要的参数。

我们拿出以前写过的栈的数据空间的初始化以及增容的代码:

void StackBuy(Stack* ps, int init_num = 4)
{assert(ps);ps->capacity = ps->capacity == 0 ? init_num : 2 * ps->capacity;StackDataType* tmp = (StackDataType*)realloc(ps->data, ps->capacity * sizeof(StackDataType));if (tmp == NULL){printf("realloc failed\n");return;}ps->data = tmp;
}

这里,我们让栈的data的元素数量默认是4,但是如果你想要让它是8或者16的时候,多传一个参数就行了!

5.2.缺省参数的分类

缺省参数可以分成全缺省参数和半缺省参数

  • 全缺省参数
void TestFunc(int a = 10, int b = 20, int c = 30)
{cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl;
}
  • 半缺省参数
void TestFunc(int a, int b = 10, int c = 20)
{cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl;
}

5.3.缺省参数的注意点

  • 注意1:半缺省参数必须从右到左依次地连续地给出,不能有间隔,下面就是错误的声明方式:
void TestFunc(int a, int b = 10, int c)
{cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl;
}

  • 注意2:缺省参数不能在函数声明和定义中同时出现。
    比如int a = 10仅需在声明或定义的地方写一次就行了。



  • 注意3:缺省值必须是常量或者全局变量

6.函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。

学校期末考试考完了,出考场后:

学霸:“考试完了。”
学渣:“考试完了。”

嘿嘿,虽然这两句话读起来一样,但表达的意思可不一样哦!

C++里面也有一函数多义的情况!

6.1.函数重载的概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数类型顺序)必须不同,常用来处理实现功能类似数据类型不同的问题

  • 参数类型不同
int Add(int left, int right)
{return left + right;
}
double Add(double left, double right)
{return left + right;
}
long Add(long left, long right)
{return left + right;
}
  • 参数个数不同
int Add(int n1, int n2)
{return n1 + n2;
}
int Add(int n1, int n2, int n3)
{return n1 + n2 + n3;
}
  • 参数顺序不同(个人认为没啥diao用)
int Add(int n1, double n2)
{return n1 + n2;
}
int Add(double n1, int n2)
{return n1 + n2;
}

6.2.函数重载的注意点

请特别注意,返回值不同,函数名及参数相同的函数不能重载!

short Add(short left, short right)
{return left + right;
}
int Add(short left, short right)
{return left + right;
}

这就不属于函数重载

6.3.为什么C++支持函数重载------名字修饰

我们说函数重载是C语言不具有的功能,而C++添加了这个功能?

函数重载究竟是怎么实现的呢?

这就要从我们的底层函数调用讲起了
在C/C++中,一个程序要运行起来,分为预处理,编译,汇编,链接四个步骤

让我们尤其来关注链接这一步
链接时,当一个文件f1的某一行代码调用了文件f2中的函数a时,编译器看到f1调用了a,但是f1中找不到a的地址,于是,编译器就去f2的符号表中寻找a的地址,发现能够找到,然后便把a和f1链接到一起

那么编译器根据什么去寻找函数的呢?
答案是 通过编译后的函数名修饰,对应函数的地址,通过地址,最后找到函数

我们在Linux下分别使用gcc和g++编译器看一下文件a.c和test.c链接后的反汇编源码

我们来看C语言编译器gcc编译链接后的结果:

我们可以看到,gcc编译器的函数名修饰只与函数名本身有关而与函数参数无关,所以C语言不支持函数重载,因为即使重载了你也无法让编译器去通过参数的不同在链接时找到不同的函数!


我们来看C++编译器g++编译链接后的结果:


我们可以看到,g++编译器通过函数名修饰规则将符号表中的函数符号修饰成了_Z3Addii的形式
_Z3代表函数名长度
Add代表函数名
ii代表有2个参数int和int

这样参数不同的同名函数在符号表中被修饰成了不同的符号,这就能在链接时轻松找到不同函数了!

6.4.小结

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。

而C++是通过函数修饰规则来区 分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

另外我们也理解了,为什么函数重载要求参数不同!而跟返回值没关系。

7.extern “C”

C++编译器能识别C++函数名修饰规则,也能识别C函数名的修饰规则

有的时候,在C++工程中可能需要将某些函数按C的风格编译,那么,我们只要在函数前面加 extern “C” ,意思是告诉编译器,将该函数按C语言规则来编译

请注意,extern “C”要在函数声明以及定义的地方都加上,不能只加一个地方,否则就会报错!

8.引用

8.1.引用的概念

先看一段代码:

int main()
{int a = 10;int& ra = a;
}

这里,ra就是a的引用。

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

比如,特朗普本名唐纳德·特朗普,但在中国,被叫做懂王,懂王就是他的别名

引用的格式如下:

类型& 引用变量名(对象名) = 引用实体;

8.2.引用的特性

  1. 引用在定义时必须初始化,这是不对的:
 int& ra;
  1. 一个变量可以有多个引用,引用也可以有引用
 int a = 10;int& ra = a;int& ra2 = a;int& rra = ra;
  1. 一个引用一旦引用了一个实体,就不能引用另一个实体,看以下代码:
 int a = 10;int& ra = a;int b = 20;ra = b;

ra = b;并不是让ra从a的引用变成b的引用,而是将b赋值给ra

8.3.常引用

首先我们提一句话:

引用时,别名的权限能够减小或者不变,但不能放大

void TestConstRef()
{const int a = 10; int& ra = a; //a被const修饰,表示a不能被改;而ra是a的引用,ra并没有说明自己不能被改,这时ra的权限被放大了,所以编译报错
}void TestConstRef()
{const int a = 10; const int& ra = a; //这样写才是对的
}
void TestConstRef()
{int& ra = 10; //10是常量不能被修改,而ra却是可以被修改,权限被放大了const int& ra = 10; //这样写才是对的
}
void TestConstRef()
{double d =1.234;int& rd = d;//这里涉及到整型提升,将double转换为int时,提升完了的值存放在一个具有常性的临时变量里,所以右边是常数,左边是变量,左边权限过大const int& rd = d;//这样写才是对的
}

所以引用前加const的好处是:

  1. 保护形参
  2. 能够传普通对象,也能够传常量

8.4.引用做参数

  • 输出型参数·
void Swap(int& left, int& right)
{int temp = left; left = right; right = temp;
}
  • 参数变量较大时,引用参数可以减少拷贝;如果形参在函数中不被改变时,建议 const Type&

8.5.引用做返回值

先看一段错误的代码


int& Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int& ret = Add(1, 2); Add(3, 4); cout << "Add(1, 2) is :" << ret << endl; return 0;
}

运行结果是7.
Why?
首先我们要知道函数被调用时会建立栈帧,函数被执行完时栈帧就会被销毁,那么返回值是怎么被从Add函数中返回到main函数中的呢?你不是说Add函数 执行完return c; 之后栈帧就被销毁了吗?c是怎么被传递出来的呢?哦,传值返回时,会为返回值开辟一个临时变量,这个临时变量还未还给操作系统,那么使用引用返回,就能把这块地址上的值返回出去。这还是很危险的,万一已经返还给操作系统了呢,内存已经被清空了呢?

于是,我们假设临时变量的地址为0x8822ff44,第一次该地址上的值被置为3
同时,ret对应地址0x8822ff44
第二次调用Add,0x8822ff44上的值又被改为7
于是,ret对应的值就是7了

9.内联函数

9.1.概念

在C++中,内联函数被用来替代宏函数

inline Add(int a, int b)
{return a + b;
}

以inline修饰的函数叫内联函数,编译时C++编译器会在调用函数的地方展开,没有建立栈帧的开销,提升了程序运行的效率。

9.2.特性

  1. inline是一种以空间换时间的做法,适合10行代码以内的函数
  2. 代码太长、包含循环/递归时,编译器会自动忽略内联展开
  3. 内联函数的声明和定义要放在一个文件中

10.auto关键字(C++11)

来看这样一段代码:

int a = 1;
char b = 'y';
auto c = a;
auto d = b;

auto关键字帮助我们通过右边的赋值,自动判断左边声明的变量的类型

优点:简化了代码
缺点:降低了代码的可读性

我们可以通过打印 typeid(变量).name() 来查看变量的类型

请注意:

  • 用auto声明指针时,auto和auto*是一样的;
    而声明引用是,必须要用auto&
int main()
{int x = 10; auto a = &x;auto* b = &x;auto& c = x;
}
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对 第一个类型进行推导,然后用推导出来的类型定义其他变量。以下代码是不对的:
int main()
{auto a = 3, c =4.0;
}
  • 以下场景下auto都不能用于类型自动推导:
void TestAuto(auto a)
{}
void TestAuto()
{int a[] = {1,2,3}; auto b[] = {4,5,6};
}

auto不能用来声明数组,因为编译器不知道要申请多少字节的空间,后面的 3 究竟是short还是int还是long long?

11.范围for

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。

因此C++11中 引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:
第一部分是范围内用于迭代的变量,
第二部分则表示被迭代的范围。

注意:for循环迭代的范围必须是确定的

int main()
{int arr[] = { 1,2,3,4,5,6 };for (auto e : arr)cout << e << endl;
}

12.nullptr

好的编程习惯应该是,在声明一个变量的时候,给它赋一个合适的初值。
在对指针进行初始化的时候,我们在C语言中常常这样做:

 int p = NULL;

NULL在C语言里是空指针,值为0,类型是(void*),代表地址0x00000000

而我们看到C的头文件<stddef.h>内,有这样一段代码,告诉我们NULL其实是一个宏:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
#endif

这段代码告诉我们,我们用C编译器,NULL就是0处的地址;用C++编译器,NULL就是一个字面常量0,没有指针的属性

以下情况下,NULL的使用就会产生麻烦:NULL被当作int 类型的0,而不是0x00000000

void f(int)
{cout<<"f(int)"<<endl;
}
void f(int*)
{cout<<"f(int*)"<<endl;
}
int main()
{f(0); f(NULL); f((int*)NULL); return 0;
}

于是,C++11引入了新关键字 nullptr,代表0处地址
注意:

  1. nullptr使用时不需要包头文件
  2. sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

【C++】C++快速入门相关推荐

  1. Shiro第一个程序:官方快速入门程序Qucickstart详解教程

    目录 一.下载解压 二.第一个Shiro程序 1. 导入依赖 2. 配置shiro配置文件 3. Quickstart.java 4. 启动测试 三.shiro.ini分析 四.Quickstart. ...

  2. 计算机入门新人必学,异世修真人怎么玩?新手快速入门必备技巧

    异世修真人怎么快速入门?最近新出来的一款文字修仙游戏,很多萌新不知道怎么玩?进小编给大家带来了游戏新手快速入门技巧攻略,希望可以帮到大家. 新手快速入门攻略 1.开局出来往下找婆婆,交互给点钱,旁边有 ...

  3. Spring Boot 2 快速教程:WebFlux 快速入门(二)

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘 ...

  4. Apache Hive 快速入门 (CentOS 7.3 + Hadoop-2.8 + Hive-2.1.1)

    2019独角兽企业重金招聘Python工程师标准>>> 本文节选自<Netkiller Database 手札> 第 63 章 Apache Hive 目录 63.1. ...

  5. 《iOS9开发快速入门》——导读

    本节书摘来自异步社区<iOS9开发快速入门>一书中的目录,作者 刘丽霞 , 邱晓华,更多章节内容可以访问云栖社区"异步社区"公众号查看 目 录 前 言 第1章 iOS ...

  6. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 序

    BIML 101 - BIML 快速入门教程 做大数据的项目,最花时间的就是数据清洗. 没有一个相对可靠的数据,数据分析就是无木之舟,无水之源. 如果你已经进了ETL这个坑,而且预算有限,并且有大量的 ...

  7. python scrapy菜鸟教程_scrapy学习笔记(一)快速入门

    安装Scrapy Scrapy是一个高级的Python爬虫框架,它不仅包含了爬虫的特性,还可以方便的将爬虫数据保存到csv.json等文件中. 首先我们安装Scrapy. pip install sc ...

  8. OpenStack快速入门

    OpenStack云计算快速入门(1) 该教程基于Ubuntu12.04版,它将帮助读者建立起一份OpenStack最小化安装.我是五岳之巅,翻译中多采用意译法,所以个别词与原版有出入,请大家谅解.我 ...

  9. Expression Blend实例中文教程(2) - 界面快速入门

    上一篇主要介绍Expression系列产品,另外概述了Blend的强大功能,本篇将用Blend 3创建一个新Silverlight项目,通过创建的过程,对Blend进行快速入门学习. 在开始使用Ble ...

  10. 图文并茂!60页PPT《快速入门python数据分析路线》(附链接)

    一个月不走弯路快速入门学python和python数据分析路线,呕心沥血加班加点做了2天,一共63页,该课件讲的都是路线中的核心知识,今天把该PPT分享给大家,能根据该课件提到的知识有针对性的学,做到 ...

最新文章

  1. 学习如何在AutoCad土木工程中绘制建筑设计图
  2. WEB 打印的相关技术分析
  3. 家庭局域网开启AP隔离利用无线路由器互连
  4. NSIS 打包 win7 中无法删除快捷方式
  5. c#实现 改进弧长法判断点在多边形里面
  6. 图像间距pitch是什么?(linesize、stride)(指图像中的一行图像数据所占的存储空间的长度)
  7. 深入ASP.NET数据绑定(上)
  8. 做移动互联网App,你的测试用例足够吗?
  9. tomcat中设置Java 客户端程序的http(https)访问代理
  10. OSL LLVM 3.3 Related Changes
  11. python手绘效果图_2020高校邦《马克笔手绘效果图》判断题答案2020高校邦《网络数据采集与Python爬虫(山东大学定制班级)》见面课测试答案...
  12. 【kafka】kafkaProducer 拉取元数据的流程
  13. 戴尔企业级技术社区达人积分等级制度
  14. 为何马云“惧怕”沃尔玛
  15. 标准 C I/O函数
  16. 统计学习方法c++实现之二 k近邻法
  17. 计算机操作基本技能知识,计算机基本操作技能考核知识点
  18. java怎么判断字符串是否为空的几种方法
  19. 重磅|如何利用NBA球员推文预测其球场表现?
  20. 为什么证券投资是世界上最难成功的行业

热门文章

  1. 支付系统设计四:支付核心设计03-快捷发送短信(失败转代扣)
  2. 二十岁和三十岁的女生!脱单或者谈一场恋爱还是先脱穷?女孩子就应该好好奋斗
  3. Linux中bash下三种引号的作用(双引号,单引号,反引号)
  4. sourceTree打不开,启动闪退
  5. GMC云服务器 性能测评
  6. Django 源码: 中间件(middleware)
  7. WindowsAPI —— CreateMutex
  8. 微博营销事件背后的真与假
  9. 我的CSDN直播首秀来了:技术分享成就精彩程序人生(直播间还送福利哦)
  10. CNN中feature map、卷积核、卷积核个数、filter、channel的概念解释,以及CNN 学习过程中卷积核更新的理解