C++:从C到C++的飞跃之旅(C++基础知识)

残风也想永存 2024-07-26 09:35:01 阅读 92

        本期博客是一篇C++基础知识,对后续C++的深入学习,都是有着相当重要的地位❤,内容包含了以下知识:命名空间、C++的输入&输出流、缺省参数、重载函数、引用、inline(内联函数)、nullptr(主要解决C语言NULL类型混淆的问题)

        如果这篇博客对大家有帮助,还请点赞收藏❤,感觉大家的支持~,我会更加努力的❤

一、命名空间

1.问题导向

<code>#include<stdio.h>

#include<stdlib.h>

int rand = 1314;

int main()

{

printf("%d\n", rand);

return 0;

}

/*

*这组代码中,就存在了一个不可避免的 会存在编译错误:

*error C2365: “rand”: 重定义;以前的定义是“函数

*warning C4477: “printf”: 格式字符串“%d”需要类型“int”的参数,但可变参数 1

*拥有了类型“int (__cdecl *)(void)”  

*/

        不难理解,rand是生成随机数的函数名,其函数的声明存放于头文件<stdlib.h>中,而我们又定义了一个全局变量rand;这就导致了上面的错误,我们称为命名冲突;

问:自己写代码的时候,命名稍加注意一下,不就可以了吗?回:虽然你自己写代码的时候,不会发生命名冲突的问题,但你不能保证,多人协作写一个项目的时候,不会出现命名冲突的问题,毕竟每个人的想法都是参差不齐的。

        为了解决命名冲突的问题,C++引入了一个新的关键字——namespace,namespace后跟一对{},中间用于变量的定义,函数的声明与定义,类的声明与定义等等;可以为我们在全局域生成一个命名空间域;主要用于解决命名冲突、组织代码、提高代码的可读性和可维护性

        下面的代码,是在域中定义一个malloc为函数名的交换函数,和以rand为变量名的变量。包含头文件<stdlib.h>后,编译器不会报上面的错误。

2.namespace的定义

namespace的本质,在用途方面,可以类似于电脑分盘(新建文件夹),在不同的盘符(文件夹)中可以定义相同的文件标识;不同的域可以使用相同的标识符,如局部域和作用域,都可以定义变量a;在同一域中,不能出现两个或两个以上的相同的标识符多文件中,存在相同的命名空间域名的时候,编译的时候,会形成同一个域;namespace可嵌套使用;namespace只可在全局域中使用;C++的作用域主要有四种,函数局部域、全局域、命名空间域、类域。函数局部域、全局域会改变变量或函数的作用域和生命周期,而命名空间域、类域只改变其作用域,不改变其生命周期;C++的标准域,定义在 std 域中;编译器找变量、函数、或类的出处,默认是局部域和全局域(先局部域,后全局域);若找不到,则编译器报错;——由此更能体现命名空间对命名冲突问题的解决;下面将对上面所说的某些现象,进行验证与反馈~,若无问题可直接跳转命名空间的使用

<code>//.h文件

#include<stdio.h>

namespace zmh

{

void Print();

}

//.cpp文件

#include"zmh.h"

namespace zmh

{

void Print()

{

printf("残风也想永存:第一个C++代码\n");

}

}

//.main文件

#include"zmh.h"

using namespace zmh; // 这里是对命名空间的一种使用方法

int main()

{

//验证:多文件中,存在相同的命名空间域名的时候,编译的时候,会形成同一个域;

//若成功调用Print(),则验证成功!!!

Print();

return 0;

}

3.命名空间的使用

        我们已经知道,编译器找变量、函数、或类的出处,默认是局部域和全局域(先局部域,后全局域);那我们就想,怎么才能告诉编译器,去全局域,去找出处呢?

        答案是有的,这里将学习一个新的操作符 ‘::’——作用域解析操作符,而是用于指定某个标识符的所属作用域或命名空间的特殊符号。

        ‘::’,操作符前是全局域(双冒号前面什么都没有,则代表全局域)或者是命名空间的域名,后面则是我们要访问的变量,函数或类。

         命名空间使用总结:

        注: ‘::’不仅仅可以访问全局域和命名空间域,但目前们只需要掌握这两个用途即可  

        如果我们对命名空间域中某一个变量或函数的使用率更频繁的时候,每次都要通过上面的访问方式,是不是有点太过繁琐了?难到就没有其它的解决方法了吗?

        是有的,C++为我们提供了一个using关键字,在全局域中使用using关键字,可以解决上面的问题。

其使用方法由以下两种:

using (命名空间域名)::(要访问的变量、函数或类);   

// 对某个要频繁使用的变量、函数或类进行展开

using namespace (命名空间域名); 

// 对整个命名空间域进行展开

功效,可以让我们在使用某个变量、函数或类的时候,不再需要 (命名空间域名)::(要访问的变量、函数或类) ,而是直接(要访问的变量、函数或类)即可。

命名空间使用总结:

命名空间使用方法一:

(命名空间域名)::(要访问的变量、函数或类)

命名空间使用方法二:

using (命名空间域名)::(要访问的变量、函数或类);   

// 对某个要频繁使用的变量、函数或类进行展开

命名空间使用方法三:

using namespace (命名空间域名); 

// 对整个命名空间域进行展开

二、C++的输入&输出流

<iostream>:是C++的标准输出、输入流的库函数头文件;其函数的声明与定义在,命名空间std中。std::cout:是C++的标准输出函数;可以通过插入运算符 <<来发送各种类型的数据。std::cin:是C++的标准输入函数;可以通过提取运算符 >> 来读取各种类型的数据。std::endl:用于在输出流中插入一个换行符,并刷新输出缓冲区;这意味着它不仅仅是插入一个换行符(<code>\n),还会确保所有等待在缓冲区中的输出都被发送到它们的目的地(如屏幕)。<<:流输出符号,用于输出数据。>>:流提取符号,用于读取数据。C++的cout与cin,会自动识别数据格式,无需,我们再像C语言的printf,scanf一样,要注意每个数据类型对应的占位符。

三、缺省参数

定义:所谓缺省参数,是针对函数形参形式来讲的;在函数声明或定义的时候,我们可以直接给形参赋值。当函数调用的时候,如果对应的实参没有被提供,那么将使用这些缺省值;反之则使用被提供的实参。(缺省参数又叫默认参数)函数声明与实现分离的时候,不能重复给缺省参数,且规定只能在函数声明的时候,给缺省参数。缺省参数分为全缺省,或半缺省;全缺省就是函数每个形参都又缺省参数,半缺省就是函数每个形参不全部都是缺省参数。C++规定,半缺省参数,只能从右向左给;且函数调用的时候,必须从左向右给值,不能跳跃给值。错误使用案例,还请大家敲入合适的代码,进行测试;下面只展示正确的使用方法,以及函数的行为。

四、重载函数

定义:在相同域中,函数名相同,但形参不同的两个或两个以上的函数构成重载函数;重载函数特征1:函数名相同,形参个数不同;重载函数特征2:函数名相同,形参类型不同;重载函数特征3:函数名相同,形参顺序不同;注意事项:不能通过返回值的不同来定义重载函数优势:允许开发者通过相同的函数名,实现形参类型、个数不同,但功能类似的函数;这提高代码的可读性,增加了代码的灵活性;同时函数调用也会显得便利。

//  形参个数不同

void ZMH(int a, double b) { ; }

void ZMH(int a, double b, int c) { ; }

//  形参类型不同

void ZMH(int a, double b) { ; }

void ZMH(int a, int b) { ; }

//  形参顺序不同

void ZMH(int a, double b) { ; }

void ZMH(double b, int a) { ; }

//  不能通过返回值的不同来定义重载函数

void ZMH(int a, double b) { ; }

int ZMH(int a, double b) { ; }

//  重载函数与缺省参数不恰当的混用,可能存在歧义

void ZMH() { ; }

void ZMH(int a = 4) { ; }

问:上面两组函数,构成重载吗?

答:构成

问:调用ZMH();的时候,是执行哪一个函数呢?

答:编译器不知道执行哪一个函数,会报错。

五、引用

1.引用的意义

        讲引用的之前,先插入一个话题:周树人与鲁迅的关系;在革命时期,周树人写的文章很多都是讽刺社会的黑暗,以及国民政党的昏庸,百姓思想的封建。可反动势力,会容忍别人的诋毁吗?当然不会,倘若周树人直接以本名去当文章的作者,说不定上午刚发布完文章,下午反动势力,就闯进家门逮捕了;于是周树人就想着,我能不能取一个别名,去发布文章呢?这样不但降低了被逮捕的风险,而且也能实现自己的目标。

        而C++的引入的引用,其价值,与周树人使用“鲁迅”这一笔名来发表文章,在某种意义上是相似的——都是为了避免直接暴露身份或对象,从而达到更安全、更灵活地执行目的的效果。

2.引用的定义   

引用并非是创建一个新变量,而是引用对象起一个别名,不占用内存空间我们可以通过引用,直接去操作引用对象。引用,可以用在函数的形参,函数的返回值,以及对某一局部变量直接使用引用。一个引用对象,可以有多个引用。引用必须初始化。(指针是推荐初始化,但可以不初始化)引用只能选择一个实体对象。(指针可以随意更改所指向的对象)

3.引用的使用

        我们在知道了引用的的重要性和概念之后,我们该如何正确使用引用呢?C++复用了C语言中的取地址操作符——&;在类型之后使用'&'则为引用。 type& 别名 = 引用对象;下面将通过代码例子进行进一步的理解。 

4.const 引用

const type& 别名 = 引用对象。const引用可以接受const对象,和普通对象,但普通的引用不能接受const对象——这遵从于权限不能放大,只能缩小。临时对象:程序运行时,会在内存开辟一个临时空间,去存储表达式求值的结果,称为临时对象,且临时对象具有常数性。const引用可以接受临时对象,从而达到延长其生命周期的效果。

5.引用的优势

引用可以做函数参数和返回值,减少拷贝提高效率;引用传参,可以实现指针传参一样的效果,但指针要通过解引用才能访问到对象;引用,是对引用对象起别名,这使得代码更加的直观,和安全。

六、inline

函数声明与定义一起的时候,在其前面加上inline关键字,使得函数在调用的时候,并不会去建立函数栈帧,而是直接在调用函数的内部,将被调用函数的代码展开。这样减少了函数创建栈帧的效率,提高的代码运行效率,此函数称为内联函数。在函数前面加上inline关键字,并非都被编译器所认可;递归函数、有些代码片段较长的函数,不触发内联函数的的机制。一般情况下,函数体小而简单,编译器才会进行内联函数的操作。inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。

七、nullptr

在C语言中,C++98中,官方将宏NULL,当作空指针的符号,有些情况是void* 类型的0,而有些情况只是0。C++中,void* 类型指针,不能隐式转换为其它类型的指针。因此在某些函数重载的时候,NULL是隐形转换为整型0时候,是对于调用重载函数是存在歧义的;而void* 类型的0,编译器会报错。所以C++11引用的nullptr关键字,此关键字总能被转换为任意类型的指针。所以nullptr当作空指针,比NULL更具有安全性。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。