在C语言里面,我们最开始学的便是输出一个“hello world”。C++实际上就是进阶版的C语言,在C++里面C语言的语法基本都通用,但C++在C语言之上创造了更多方便不一样的语法规则,也就是说,C++也有它自己的一套“hello world”。接下来我们看看C++的“hello world”如何去写。
// test.cpp C语言用 .c,C++用 .cpp。
#include<iostream>
using namespace std;
int main()
{
cout << "hello world\n" << endl;
return 0;
}
命名空间 namespace
要理解上面的代码,我们要先理解C++中为了解决C语言的命名冲突问题而创造的一个关键字 namespace 命名空间。
- 定义命名空间,需要用到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
- namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量。
- C++中域有函数局部域,全局域,命名空间域,类域。
- 项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,会将他们合并在一起,不会冲突。
- C++标准库都放在⼀个叫std(standard)的命名空间中。(也就是上面的std);
那我们平时使用变量及函数时,默认是从局部或者全局域去找,那么我们需要用到自定义的域,我们该如何去使用自定义的命名空间呢?下面有三种方式
- 指定命名空间访问,项⽬中推荐这种⽅式。
- using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
- 展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。
namespace N
{
int a=1;
int b=2;
}
//指定访问
count<<N::a<<endl;
//展开某个成员
using N::b;
count<<N::b<<endl;
//展开整个命名空间
using namespace N;
在上面的代码里面就展开了std这个命名空间,实际上就是C++的标准库,而要完全看懂上面的“hello world”代码,还涉及到C++的的输入输出知识。
C++的输入输出
- 是 Input Output Stream 的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输出对象。只有包含了这一个头文件,我们才能包含了std这个标准库。
- std::cin 是 istream 类的对象,它主要⾯向窄字符的标准输⼊流 ; std::cout 是 ostream 类的对象,它主要⾯向窄字符的标准输出流; std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。也就是相当与C语言的换行符号“\n”,只不过这个endl属于是一个函数。
- <<是流插⼊运算符,>>是流提取运算符。流插入count,通俗的讲也就是输出到控制台那里。
- C++的输入输出相比C语言方便很多,它不需要手动指定格式,C++可以自动识别变量类型,但是区别在于,<<与>>是双目操作符,只支持一个一个输入输出,也就是说字符与变量不能同时输出,要分开写。
- cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)命名空间中,所以要通过命名空间的使⽤⽅式去⽤他们。在平时的练习里我们可以直接展开std,但在项目中一般不这样做,有风险。
这样,我们就差不多能理解上面的“hello world”代码了,不过要完全展开理解这些知识,还需要涉及到许多知识面,下面一点一点学习。
缺省参数
- 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值,也就是默认值。在调⽤该函数时,如果没有指定实参则采⽤该形参的缺省值,否则使⽤指定的实参。
- 缺省分为半缺省和全缺省,全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左(不可从左往右)依次连续缺省,不能间隔跳跃给缺省值。
- 带缺省参数的函数调用时,是从左往右传实参,和给缺省相反,也是不能跳跃。
- 函数声明和定义分离时(也就是声明和定义放在两个文件里),缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
函数重载
有些函数我们需要用到不止一次,并且要使用的参数不是同一类型,但是函数实现的结果是一样的,这时候写两个不同名字的函数就看的没那么清楚那么明确了,但是C++里的函数重载就能解决这个问题。
- 在函数定义里面,与C语言不一样,C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者参数类型不同,也可以是参数类型顺序不同。
- 返回值不同不能作为重载条件,因为调⽤时也⽆法区分。
- 有些函数会构成函数重载,但在调用的时候会产生歧义,不知道调用的是哪个函数。
引用
- 引用就是取别名,可以不止一个别名,当然还能给别名取别名,相当于也是给本身取别名。
- 引用不开辟新的内存空间。
- 初始化:类型& 引⽤别名 = 引⽤的对象; 引用在定义时必须初始化。
- 引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体。
引用的使用
- 引⽤在实践中主要是于函数调用中引⽤传参和引⽤做返回值,减少拷⻉来提⾼效率和改变引⽤对象时同时改变被引⽤对象。
- 引用和指针传参类似,相对于引用方便一点,但引用不能完全替代指针,指针的改变指向引用还是做不到的。
- 在函数中,返回值在返回过程中会产生一个拷贝,这个拷贝是临时变量,也就是一个常量,是不能被改变的,但引用做返回值时,返回的是返回值的别名,这样就解决了拷贝产生的常量不能被改变的问题了,但也不是所有函数都能用引用做返回,当函数返回的是局部变量时,函数结束栈帧销毁变量跟着被销毁,这时候用引用返回相当于野指针的问题,不可取。
const引用
- const只可读不可写,在引用时,对象的访问权限只可缩小不可放大。
- 在有些场景下,引用的对象可能是临时变量,而临时对象具有常性,所以在这种情况下只能const引用,不然会权限放大。(临时变量通常是在一些未确定的表达式里产生,或者在类型转换时会产生临时变量)。
指针和引用
- 在概念上,引用只是取别名不开空间,而指针要存储一个变量的地址,要开空间。
- 引用必须要初始化,而指针没有这样的强制要求。
- 引用在引用一个对象后,不能再引用其他对象了,而指针可以不断改变指向的对象。
- 引用可以直接访问对象,而指针需要解引用才可以访问。
- 在sizeof下,引用直接就是引用类型的大小,而指针固定时地址空间的所占字节个数(32位平台下
占4个字节,64位下是8byte)。 - 指针容易出现空指针和野指针的问题,而引用相对安全,很少出现空引用的问题,除非错误使用。
- 引用和指针的底层其实是一样的,说到底都是地址的概念。
inline函数
- 用inline修饰的函数叫作内联函数,内联函数在调用的时候直接展开,不需要建立函数栈帧,进而可以使效率更加高。
- 内联函数对于编译器来说只是一个建议,在不同的编译器也不一样,一般在debug版本下不主动展开,也可以调成展开的,但始终对于编译器来说只是一个建议,当函数短小且频繁调用时,可能就会听取建议展开,但当函数非常大或者是递归函数时,这时候展开就是在捣乱了,编译器自然不会去展开。
- 设计内联函数的目的其实就是为了替代宏函数,宏函数比较容易出错,得到结果不尽人意,所以在短小且频繁调用的函数使用内联函数就很好。
- inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。
nullptr
- NULL在C++中被定义为整型常量0,或者在C语言中被定义为⽆类型指针(void*)的常量。在一些函数重载中常因为这个问题而调用错误,而在C++中也不允许⽆类型指针(void*)的写法,所以很麻烦。
- 在C++11中,引入了nullptr这个关键字,nullptr是⼀种特殊类型的字⾯量,它可以转换成任意其他类型的指针类型。这样,使⽤nullptr定义空指针就可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,⽽不能被转换为整数类型。


被折叠的 条评论
为什么被折叠?



