Cpp 01 — namespace命名空间、C++的输入与输出、缺省参数、函数重载、引用、隐式类型转换

前言:本文章主要用于个人复习,追求简洁,感谢大家的参考、交流和搬运,后续可能会继续修改和完善。

因为是个人复习,会有部分压缩和省略。

一、namespace命名空间

C++使用命名空间(namespace)来避免命名冲突。

在定义一个命名空间后,在外部未经处理是不可调用其中内容的。

命名空间会定义一个新的域,命名空间中的内容局限于该命名空间中。在链接时,相同命名空间里的东西会被合并到一起。同一域里不能定义同名的变量(不能重复定义)

命名空间可以嵌套定义。

只有展开命名空间或指定域时,才可以使用命名空间里的东西

命名空间使用方式:

1.加命名空间名称及作用域限定符。(在局部:std::cin)

2.使用using将命名空间中成员引入。(在全局:using std::cin;)

3.使用using namespace命名空间名称引入。(在全局:using namespace std;)

using namespace std;的意义:C++为了防止命名冲突,把标准库的东西都放进了std这个命名空间,这个代码的意思是展开了std该命名空间,可以使用该域里的所有东西。

使用命名空间的建议:

1.在项目中,尽量不要用using namespace std;因为可能会导致命名冲突,库里有些我们不了解的东西可能会与我们自己定义的变量名冲突。

2.一般日常练习可以使用using namespace std;

3.项目中,常用指定命名空间访问+展开。例如:using std::cin;

二、C++的输入与输出

C++中我们不需要给输入输出指定类型,因为它们可以自动识别类型

C++的输入与输出:cin、cout

头文件:<iostream>

自动识别类型的原理:函数重载+运算符重载

cout标准输出对象:控制台

cin标准输入对象 :键盘

cin与cout需要结合运算符来使用

>>:流提取运算符。提取输入的东西,并放到变量中。也就是我们所说的输入。

<<:流插入运算符。将变量插入到控制台中。也就是我们所说的打印。

平时建的项目都是控制台应用程序,是和控制台交互的。

实际上cout和cin分别是ostream和istream类型的对象,它们可以自动识别类型。

注意:

1.打印char*类型时,cout无法判断是指针还是字符串

2.流提取和流插入的运算符优先级是高于==的

三、缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值。

缺省参数分为全缺省参数和半缺省参数(部分参数缺省)。

缺省参数的特点:

1.缺省参数不能在声明和定义中同时出现,建议在声明中给。

2.因为传参数时是从左往右给的,所以给缺省时是从右往左给,并且不能有间隔。

3.缺省值必须是常量或者全局变量。

四、函数重载

函数重载即一词多义,让使用更加方便

函数重载的要求:

1.在同一作用域中

2.同名函数

3.参数列表必须不同(参数的个数或类型或顺序)

注意:

只有返回值不同时,不构成重载

只有形参的名称不同,也不构成重载

1.下面两个函数能形成函数重载吗?有问题吗或者什么情况下会出问题?

以下是运行报错

不构成函数重载,两个Func的区别是有没有给形参a缺省值,想构成函数重载对于参数的条件是: 形参的个数、类型或顺序不同,这里不符合重载的条件,所以两个其实是同一个函数,Func重复定义,报错无法运行。

当一个参数为int,一个为int&,两函数构成重载,但是调用时会有歧义。

以下这种情况构成重载,第一个add可以运行成功,但是第二个不可以

cpp 复制代码
void add(int x = 0,int y = 0,int z = 0)
{
    return x+y+z;
}
void add(int x = 0, int y = 0)
{    
    return x+y;
}

int main()
{
   add(1,2,3);
   add(1,2);
   return 0;
}

六、引用

引用不是新定义一个变量,而是给已存在的变量取别名,编译器不会为引用出来的别名开辟内存空间,而是让别名和它引用的变量共用一块内存空间。(可通过取地址看出)

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

引用类型和引用实体必须是同种类型。

引用的特性:

1.引用在定义时必须初始化(不能写成NULL)

2.一个变量可以有多个引用

3.引用一旦引用一个实体,就不能再去引用其他实体。(即作为一个变量的别名后,不能再作为其他变量的别名)。
引用在做参数或做返回值时,可以减少拷贝,提高效率,可以更好地节省空间和时间,尤其是在处理大的对象时。

深拷贝时不用引用的话,效率会比较低。

引用还可以用作swap交换

cpp 复制代码
void swap(int& left, int& right)
{
      int temp = left;
      left = right;
      right = temp;
}

指针和引用的区别

指针和引用基本相似,但二者在使用场景、语法特性、底层原理上还是有区别的。

引用和指针的不同点:

1.引用在定义时必须初始化,指针没有要求。

2.引用在初始化引用一个实体后,就不能再引用其他实体了,而一般指针可以在任何时候指向任何一个同类型实体。

3.没有空引用,但是有空指针。

4.在sizeof中的定义不同,计算引用的结果为其所引用类型的大小,而指针始终是地址空间所占的字节数(4/8)。

5.引用自增时,是引用的实体自增1,指针则是向后偏移一个类型的大小。

6.有多级指针,但是没有多级引用。

7.访问实体的方式不同,指针需要显式解引用来访问,引用是编译器自己处理,大多可以直接访问。

8.引用比指针更安全。

9.指针需要开辟空间,引用不用开辟空间(实际在其汇编实现中,引用的底层是有类似指针存地址的方式做处理的)

10.一般传参时,引用的效率更高。当参数和返回值是比较大的变量时,传引用传参和传引用做返回值还可以提高效率,只要符合条件,尽量用引用传参传返回值,并且可以避免一些深拷贝

在链式结构时,引用无法代替指针。因为引用定义时必须初始化,并且引用不能改变指向。

从语法角度而言,引用没有开空间,指针开了4/8个字节。在底层实现的角度,引用的底层是用指针实现的。


注意:

1.是否能引用要注意访问权限大小。权限可以缩小,但是不能放大。

cpp 复制代码
const int a = 10;//只读,是属于不能修改的
int& ra = a;//这样做是不行的,ra引用a属于权限放大。
//改成const int &ra = a;这样可以

int b = 10;
int& rb = b;//可以
const int& crb = b;//属于权限的缩小,可以

int c = 10;
double d = 1.11;
d = c;//可以,这里属于隐式类型转换
cpp 复制代码
//权限的平移
int a = 10;
int& b = a;

//权限放大
const int c = 20;
int& d = c;//不可以
//应该写成
const int& d = c;
//这样不可以
d = 10;

int e = 5;
const int& f = e;//可以,属于权限的缩小

2.const&有很强的接收度。一般使用数据时,即使有const,也无关权限,权限的放大和缩小只针对引用和指针。

cpp 复制代码
int i = 1;
double b = i;//这里会发生隐式类型转换
double& r = i;//不可以,因为这种类型转换中间会产生一个临时变量的,临时i把值给临时变量,临时变量把给r,而临时变量具有常性,r属于非const的,这里属于权限放大,是不允许的
const double& rr = i;//可以
cpp 复制代码
int a = 10;
int& b = a;
int x = 15;
b = x;
这里不是把b作为x的别名,而是把x的值赋给b所引用的实体(a)。
(b已经是a的实体,就不能再用它去引用其他人了) 

七、隐式类型转换

cpp 复制代码
int c = 10;
double d = 1.11;
d = c;//可以,这里属于隐式类型转换

不是直接把c给d,而是产生一个临时变量,然后把临时变量给d

cpp 复制代码
int c = 10;
double d = 1.11;
d = c;//可以,这里属于隐式类型转换
double& rc = c;//不可以
const double& brc = c;//可以
//这里rc、brc引用的并不是c(即并不是c的别名),而是c产生的临时变量,临时变量具有常性,所以加const。(该临时变量类型为double)

强制类型转换和隐式类型转换基本一样,因为他们都会产生临时变量,它们都是不改变c本身的,都是产生临时变量的。并且它们转换都不会影响c(不论是c的类型还是什么)。

cpp 复制代码
int& add(int a, int b)
{
    int c = a + b;
    return c;
}

int main()
{
    int& ret = add(1,2);//这样是编不过的
  
    return 0;
}

此时临时变量的类型为int&。传值返回返回的是c的拷贝,传引用返回返回的是c的引用

实际上,如果出了函数作用域,返回变量就不存在了,不能用引用返回

传值返回也会给值创建一个临时变量,例如return c;会创建一个c的临时变量,然后将临时变量返回。那么怎么证明它产生了临时变量呢?

cpp 复制代码
int add(int a, int b)
{
    int c = a + b;
    return c;
}

int main()
{
    int& ret = add(1,2);//这样是编不过的
    const int& ret = add(1,2);//这样可以
    return 0;
}

因为临时变量具有常性,所以加了const才能编过

当参数和返回值是比较大的变量时,传引用传参和传引用做返回值还可以提高效率,只要符合条件,尽量用引用传参做返回值,引用传参还可以避免一些深拷贝

相关推荐
雨中rain5 分钟前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
ALISHENGYA1 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法
arong_xu1 小时前
现代C++锁介绍
c++·多线程·mutex
汤姆和杰瑞在瑞士吃糯米粑粑1 小时前
【C++学习篇】AVL树
开发语言·c++·学习
DARLING Zero two♡2 小时前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
CodeClimb2 小时前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
奶香臭豆腐2 小时前
C++ —— 模板类具体化
开发语言·c++·学习
不想当程序猿_2 小时前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
cdut_suye3 小时前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
波音彬要多做3 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法