自学内容网 自学内容网

C++:C与C++的衔接课(C++基础知识,还请点赞收藏❤)

一、前言

        我们都知道,C++是C语言的前身,C++里面的很多语法,都来自于C语言,C++的语法是完全兼容于C语言的。可是,又有一个疑问?有什么问题是非C++不可的呢?

        下面,我们将以不破不立的原则,进而铺垫C++的基础知识,并展开讲解。

二、命名空间

1.问题导向
#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 域中
  • 编译器找变量、函数、或类的出处,默认是局部域和全局域(先局部域,后全局域);若找不到,则编译器报错;——由此更能体现命名空间对命名冲突问题的解决;
  • 下面将对上面所说的某些现象,进行验证与反馈~,若无问题可直接跳转命名空间的使用

//.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:用于在输出流中插入一个换行符,并刷新输出缓冲区;这意味着它不仅仅是插入一个换行符(\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更具有安全性。

原文地址:https://blog.csdn.net/FSRMWK/article/details/140356067

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!