【C++】入门(一):命名空间、缺省参数、函数重载

目录

一、关键字

二、命名空间

问题引入(问题代码):

域的问题

1.::域作用限定符 的 用法:

2.域的分类

3.编译器的搜索原则

命名空间的定义

命名空间的使用

举个🌰栗子:

1.作用域限定符指定命名空间名称

2. using 引入命名空间中的成员 即 展开命名空间中某一个

3. usinng namespace 命名空间名称 展开命名空间

三、C++输入、输出

四、缺省参数

概念

全缺省参数

半缺省参数

实践中的应用场景🌰举个例子:

声明和定义分离

回顾 声明 和定义的概念

再来分析上述程序

理解编译与链接的过程

理解函数与文件的关系

五、函数重载

代码示例:

C++是如何支持函数重载的?

函数名修饰


一、关键字

asmdoifreturntrycontinue
autodoubleinlineshorttypedeffor
booldynamic_castintsignedtypeidpublic
breakelselongsizeoftypenamethrow
caseenummutablestaticunionwchar_t
catchexplicitnamespacestatic_castunsigneddefault
charexternoperatorswitchvirtualregister
constfalseprivatetemplatevoidtrue
const_castfloatprotectedthisvolatilewhile
deletegotoreinterpret_cast

增加的关键字: C++增加了一些关键字来支持面向对象编程(如类、继承、多态等)和模板编程。例如,class,public,protected,private,virtual,friend,template,typename等。这些关键字没有在C语言中。

类型增强:C++增加了一些用于类型安全和方便的关键字,如bool,true,false,using,namespace等。

异常处理:为了支持异常处理,C++引入了try,catch,throw等关键字。

新的转换操作符:C++提供了static_cast,dynamic_cast,const_cast和reinterpret_cast等关键字进行类型转换,这是C语言中所没有的。

增强的存储类说明符:C++引入了mutable和thread_local等存储类说明符。

模板编程:为了支持泛型编程,C++增加了template和typename关键字。

新增运算符:C++还定义了如new,delete等用于动态内存管理的关键字,这些在C中通常通过库函数如malloc和free来实现。

特殊成员函数关键字:C++还有如default和delete等关键字,用于特殊成员函数的声明,这样设计是为了提供更好的控制。

二、命名空间

问题引入(问题代码):

下面代码存在命名冲突 : rand变量 和头文件<stdlib.h>中声明的函数 rand() 名字相同 导致冲突。

#include<stdio.h>
#include<stdlib.h>   /*rand*/
int rand = 0;
// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespaceguan来解决
int main()
{printf("%d\n",rand);return 0;
}

域的问题

1.::域作用限定符 的 用法:

限定符左边是哪一个域名 就限定了访问该变量的范围

左边是空 默认是全局域

2.域的分类

  • 全局域

  • 局部域:如果不用限定符,默认访问局部域 局部优先

  • 命名空间域:为了防止命名冲突 eg.全局定义两个同名变量 ,防止重定义,C++提出就用关键字namespace把他们定义在不同命名空间域中。

  • 类域

    注意:

    全局域、局部域既会影响生命周期,也会影响访问。命名空间只影响访问

3.编译器的搜索原则 

 1️⃣当前局部域 2️⃣全局域 3️⃣如果指定了,直接去指定域搜索

命名空间的定义

正常定义

 // 正常的命名空间定义
namespace hhh
{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};}

嵌套定义

举个栗子🌰:

namespace aaa
{namespace bbb{void Push(){cout<<"zs"<<endl;}}namespace ccc{void Push(){cout<<"yyy"<<endl;}}
}
int main()
{//嵌套定义在命名空间的同名函数 各自调用bit::bbb::Push();bit::ccc::Push();return 0;
}

ps:命名空间可以重名,编译器会把他们合并,只要命名空间内部不冲突就可以

命名空间的使用

命名空间到底该如何使用?

举个🌰栗子:

namespace yyy
{//命名空间中定义 变量 / 函数 /类型int a = 0;int b= 1;int Add(int left,int right){return left+right;}struct Node{struct Node* next;int val;};
}

1.作用域限定符指定命名空间名称

//指定访问
int main()
{//::作用域限定符printf("%d\n",yyy::a);return 0;
}

2. using 引入命名空间中的成员 即 展开命名空间中某一个

//展开一个
using yyy::b;
int main()
{printf("%d\n",yyy::a);//不可以 因为此时只展开了一个成员变量printf("%d\n",b);
}

3. usinng namespace 命名空间名称 展开命名空间

展开命名空间 影响的是 域的搜索规则。不展开命名空间,默认情况编译器只会在局部域、全局域搜索。展开命名空间就可以在命名空间里搜索。

//展开全部
using namespace yyy;
int main()
{printf("%d\n",yyy::a);//指定去该命名空间找变量aprintf("%d\n",b)
}

注意:

1. 日常练习展开为了方便使用可以展开std,实际工程实践中慎重使用!

2.展开命名空间 不是 等同于引入全局变量!

3.展开命名空间 跟 包含头文件 也有本质区别,包含头文件 在预处理过程中本质是拷贝头文件的内容

三、C++输入、输出

解释Hello world代码

//包含标准输入输出流库
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;int main(){//cout和cin是全局的流对象,细说分别是ostream和istream类型的对象// <<是流插入运算符,>>是流提取运算符//endl是C++符号,表示endline换行//他们都包含在包含<iostream>头文件中cout<<"Hello world!!!"<<endl;return 0;}

说明:使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件 以及按命名空间使用方法使用std。

补充:std命名空间的使用习惯

1.日常练习:直接展开 using namespace std

2.项目开发:std::cout 使用时指定命名空间 + using std::cout 展开常用库对象

C++ 输入输出 自动识别变量类型 

  • 示例代码:
    #include <iostream>
    using namespace std;
    int main()
    {int a;double b;char c;// 可以自动识别变量的类型cin>>a;cin>>b>>c;cout<<a<<endl;cout<<b<<"  "<<c<<endl;return 0;
    }
    • 说明

cin>>a;这行代码从标准输入流(键盘)中接受一个整数,并将其存储在变量a中。cin会根据提供的变量类型自动解释输入数据。cin>>b>>c;这行代码首先从标准输入流中接收一个双精度浮点数,并将其存储在变量b中,然后接收一个字符并存储在c中。 

四、缺省参数

  • 概念

    声明或定义函数时为函数的参数指定缺省值。缺省值就是给形参设置一个默认值。调用函数时,如果没有指定实参,则使用参数的默认值。

    缺省值必须是 常量或者全局变量。一般使用常量。

    void Func(int a = 0)
    {cout<<a<<endl;
    }
    int main()
    {Func();    //没有传参 使用参数默认值 Func(10);  //传参时 使用指定的实参return 0;
    }
  • 全缺省参数

    void Func(int a = 10, int b = 20, int c = 30)
    {cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;
    }
    调用Func()时,可以这样给参数int main()
    {Func(1,2,3);Func(1,2);Func(1);Func();//注意:不可以跳越传值//Func(,1,2);return 0;
    }
  • 半缺省参数

    注意:只能从右往左连续给缺省值,这样调用保证传的实参顺序不存在歧义

    void Func(int a, int b = 20, int c = 30)
    {cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;
    }
    //调用 同样不能跳越给
    int main()
    {Func(1,2,3);Func(1,2);Func(1);
    }

实践中的应用场景🌰举个例子:

struct Stack
{int* a;int size;int capacity;//...
};
//StackInit()改造为半缺省函数 使得可以适用更多的需要开辟空间的场景
void StackInit(struct Stack* ps,int n=4)
{ps->a=(int*)malloc(sizeof(int)*n);
}
int main()
{struct Stack st1;//缺省参数 使得函数可以适应不同场景 // 1、确定要插入100个数据StackInit(&st1, 100);  // call StackInit(?)
​// 2、只插入10个数据struct Stack st2;StackInit(&st2, 10);   // call StackInit(?)
​// 3、不知道要插入多少个 //这时就可以使用函数定义里提供的 参数缺省值 //不知道插入多少个 可以先初始化四个空间struct Stack st3;StackInit(&st3);
​return 0;
}
  • 声明和定义分离

    回顾 声明 和定义的概念

    • 函数声明告诉编译器函数的名称、返回类型以及参数列表(类型、顺序和数量),但不涉及函数的具体实现。函数声明经常出现在头文件(.h)中

    • 函数定义:提供了函数的实际实现,它包括函数的主体,即函数被调用时将执行的具体代码。函数定义包含了函数声明的所有信息,并加上了函数体

    //Stack.h 声明
    struct Stack
    {int* a;int size;int capacity;//...
    };
    void StackInit(struct Stack* ps,int n=4);//*注意 必须在声明中给出缺省值
    void StackPush(struct Stack* ps,int x);
    //Stack.cpp 定义
    void StackInit(struct Stack* ps,int n)//*注意声明和定义中缺省值不能同时给
    {ps->a=(int*)malloc(sizeof(int)*n);
    }
    void StackPush(struct Stack* ps , int x)
    {}
    //Test.cpp
    #include"Stack.h"
    int main()
    {struct Stack st1;// 1、确定要插入100个数据StackInit(&st1, 100);  // call StackInit(?)//此时包含了头文件,Test.cpp只有函数声明 用这个函数的名字找到该函数的地址 编译阶段会检查调用该函数是否存在匹配的函数,经过检查 匹配// 2、只插入10个数据struct Stack st2;StackInit(&st2, 10);   // call StackInit(?)// 3、不知道要插入多少个 struct Stack st3;StackInit(&st3);return 0;
    }

    但是试想一下,1️⃣如果缺省值只在函数定义中给出,编译阶段 无法用这个函数的名字找到该函数的匹配 ,因为调用传参跟函数声明并不匹配。另一种情况,2️⃣如果在函数的声明和定义中都指定了缺省参数编译器也可能不确定应该使用哪个版本的默认值为了避免这种情况,C++标准规定了缺省参数应当只在一个地方指定:

    • 如果函数声明在头文件中进行,那么就在头文件中的声明处指定缺省参数

    • 如果函数没有在头文件中声明(例如,完全在一个.cpp文件内定义),那么就在函数定义处指定缺省参数

    综上,

    1️⃣在项目中,声明和定义应当分离,缺省值一定要在函数声明中给出!因为,编译阶段只有函数声明,从而保证编译阶段是没有问题的。

    2️⃣声明和定义分离,导致编译阶段无法找到函数的定义,没有函数的地址。

  • 再来分析上述程序

    • 理解编译与链接的过程

      1️⃣预处理阶段 :展开头文件、宏替换、条件编译、删除注释

      对于每个.c文件,编译过程从预处理开始。预处理器会处理以#开头的指令,例如#include "stack.h"会将stack.h中的内容文本上粘贴到stack.ctest.c文件中,这样stack.ctest.c就可以看到这些函数声明了

      2️⃣编译:检查语法➡️生成汇编代码

      编译器接着编译每个.c源文件,将它们转换成目标代码(通常是机器代码的一种中间形态,称为目标文件,扩展名为.o或.obj)。此时,编译器确保源代码符合语法规则,对每个源文件进行类型检查,确保所有函数调用都符合其声明,但还不解决跨文件的函数引用问题。例如,stack.c被编译成stack.o,test.c被编译成test.o

      3️⃣汇编:汇编代码➡️二进制机器码

      4️⃣链接:合并、有些地方要用函数名去其他文件找函数地址

      一旦所有的源文件被编译成目标文件,链接器(linker)负责将这些目标文件以及必要的库文件链接成一个单一的可执行文件。在链接过程中,如果test.c(对应的是test.o)调用了stack.c中(对应的是stack.o)的函数,链接器负责“修补”这些调用,使得test.o中的调用可以正确地连接到stack.o中定义的函数上,链接器确保所有外部引用都能正确解析到它们所引用的实体。

    • 理解函数与文件的关系

      • 在stack.h中声明的函数,让其他源文件知道这些函数的存在、它们的参数以及返回值类型。stack.h扮演了接口的角色。

      • stack.c提供了stack.h中声明的函数的具体实现。test.c作为使用这些函数的客户端代码,通过#include "stack.h"能够调用这些函数。

      • 编译过程中,test.c和stack.c分别被编译成中间的目标文件。这些目标文件中的函数调用尚未解析到具体的地址

      • 在链接过程,链接器解析这些调用,使得从test.o中的调用可以正确地定位到stack.o中的函数定义,从而生成一个完整的可执行文件,所有的函数调用都被正确地解析和连接,这个地址修正的过程也叫做重定位

五、函数重载

C语言不允许同名函数

C++允许同名函数。要求:函数名相同,参数不同,构成 函数重载

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

代码示例:

#include<iostream>using namespace std;// 1、参数类型不同
int Add(int left, int right)
{cout << "int Add(int left, int right)" << endl;return left + right;
}
double Add(double left, double right)
{cout << "double Add(double left, double right)" << endl;return left + right;
}// 2、参数个数不同
void f()
{cout << "f()" << endl;
}
void f(int a)
{cout << "f(int a)" << endl;
}// 3、参数类型顺序不同
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}
int main()
{Add(10, 20);Add(10.1, 20.2);f();f(10);f(10, 'a');f('a', 10);return 0;
}

C语言不支持重载 链接时,直接用函数名去找地址,有同名函数的情况则区分不开。

  • C++是如何支持函数重载的?

    通过函数名修饰实现的,只要函数参数不同,函数名就会被修饰成不同。然后直接用修饰好的名字,去找该函数的地址。

    • 函数名修饰

      名字修饰是编译器自动进行的一种处理过程,它将C++源代码中的函数名和变量名转换成包含更多信息的唯一标识符。这些信息通常包括函数的参数类型、参数数量等,甚至可能包括所属的类名(对于类成员函数),通过这种方式,每个重载的函数都会被赋予一个独一无二的名字,确保链接器在最后链接程序的时候能够区分它们

Linux下g++的修饰规则简单易懂,下面我们使 用了g++演示了这个修饰后的名字。 通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度 +函数名+类型首字母】。

  • 采用C语言编译器编译后结果

 

结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。

  • 采用C++编译器编译后结果

 

结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。

通过以上这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修 饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/19963.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

K210视觉识别模块学习笔记3:内存卡写入拍摄图片_LED三色灯的操作_按键操作_定时器的配置使用

今日开始学习K210视觉识别模块: LED三色灯的操作_按键操作_定时器的配置使用_内存卡写入拍摄图片 亚博智能的K210视觉识别模块...... 本文最终目的是编写一个按键拍照的例程序&#xff1a; 为以后的专用场景的模型训练做准备&#xff0c;因为训练自己的模型需要大量的图片&a…

编译安装PHP服务(LAMP3)

目录 1.初始化设置&#xff0c;将安装PHP所需软件包传到/opt目录下 &#xff08;1&#xff09;关闭防火墙 &#xff08;2&#xff09;上传软件包到/opt目录 2.安装GD库和GD库关联程序&#xff0c;用来处理和生成图片 3.配置软件模块 4.编译及安装 5.优化把PHP 的可执行程…

nginx的安装001

Nginx是一款高性能的HTTP和反向代理服务器&#xff0c;以及邮件代理服务器&#xff0c;由 Igor Sysoev 开发并公开发布于2004年。Nginx以其高并发处理能力、低内存消耗和稳定性著称&#xff0c;特别适合部署在高流量的网站上。 操作系统&#xff1a; CentOS Stream 9 安装步骤…

企业如何利用社交媒体二维码做宣传?提升品牌形象

和普通的二维码不同&#xff0c;社交媒体二维码可以通过一个二维码链接企业的超过16的社交媒体渠道链接&#xff0c;包括&#xff1a;企业官网、小程序、公众号、淘宝店铺、抖音链接、小红书链接、美团链接、饿了么链接…等等。扫描之后&#xff0c;可以在这个社交媒体二维码界…

校园志愿者|基于SprinBoot+vue的校园志愿者管理系统(源码+数据库+文档)

校园志愿者管理系统 目录 基于SprinBootvue的校园志愿者管理系统 一、前言 二、系统设计 三、系统功能设计 1 系统功能模块 2管理员功能 3志愿者功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&a…

12.RedHat认证-Linux文件系统(下)

12.RedHat认证-Linux文件系统(下) swap虚拟内存 我加一个硬盘做实验sdc # 创建交换分区&#xff08;不用做成逻辑卷也能灵活分区&#xff09; [rootcentos8 ~]# fdisk /dev/sdc -l Disk /dev/sdc&#xff1a;10 GiB&#xff0c;10737418240 字节&#xff0c;20971520 个扇区 …

深入理解linux文件系统与日志分析

深入理解linux文件系统与日志分析 linux文件系统: 文件是存储在硬盘上的&#xff0c;硬盘上的最小存储单位是扇区&#xff0c;每个扇区的大小是512字节。 inode&#xff1a;元信息&#xff08;文件的属性 权限&#xff0c;创建者&#xff0c;创建日期等等&#xff09; block…

【AVL Design Explorer DOE】

AVL Design Explorer DOE 1、关于DOE的个人理解2、DOE参考资料-知乎2.1 DOE发展及基本类型2.2 DOE应用场景2.3 Mintab 中的 DOE工具3、AVL Design Explorer DOE示例 1、关于DOE的个人理解 仿真和试验一样&#xff0c;就像盲人摸象&#xff0c;在不知道大象的全景之前&#xff…

Java 垃圾回收

一、概述 GC GC(Garbage Collection)&#xff0c;在程序运行过程中内存空间是有限的&#xff0c;为了更好的的使用有限的内存空间&#xff0c;GC会将不再使用的对象清除然后将其所占用的内存释放出来。 java的垃圾回收机制 Java的垃圾收集&#xff08;Garbage Collection, …

嵌入式Linux复制剪切删除指令详解

指令操作 1. cp 复制指令 a. 用法&#xff1a;cp [ 选项 ] [ 源文件或目录 ] [ 目标文件或目录 ]&#xff1b; b. 用途&#xff1a;用于复制文件或目录&#xff1b; c. 通常情况下&#xff0c;复制的都不是空文件夹&#xff0c;所以直接使用 cp 复制空文件会失败&#xff0…

臭氧浓度传感器在食品厂与制药厂中的应用

在食品厂和制药厂的生产过程中&#xff0c;消毒是一个至关重要的环节。有效的消毒可以确保产品免受微生物污染&#xff0c;从而保障消费者的健康。近年来&#xff0c;臭氧作为一种广谱杀菌剂&#xff0c;因其强效的消毒能力和低污染性&#xff0c;在食品厂和制药厂的消毒过程中…

SpringMVC:创建一个简单的SpringMVC框架

目录 一、框架介绍 两个重要的xml文件 SpringMVC执行流程 二、Vscode搭建SpringMVC框架 1、maven创建webapp原型项目 2、pom.xml下添加springmvc的相关依赖 3、在web.xml配置 4、springmvc.xml的配置 5、编写Controller控制器类 6、 编写JSP界面 7、项目结构图 一…

VS2017中使用qt翻译家,除ui界面外其他用tr包裹的字符串在翻译家中显示为乱码

1、ui界面中的中文,可以正常显示 2、其他用tr包裹的字符串,显示为乱码 3、解决 改为utf8保存。 然后更新翻译文件,重新打开发现已经ok了。 参考博客: https://blog.csdn.net/zhou714534957/article/details/124948822 https://blog.csdn.net/weixin_52689816/article/d…

PAT-1004 成绩排名(java实现)

这一关感觉还没第三关难&#xff0c;思路很清晰 题目 1004 成绩排名 读入 n&#xff08;>0&#xff09;名学生的姓名、学号、成绩&#xff0c;分别输出成绩最高和成绩最低学生的姓名和学号。 输入格式&#xff1a; 每个测试输入包含 1 个测试用例&#xff0c;格式为 第 1 行…

【算法】宵暗的妖怪

✨题目链接&#xff1a; 宵暗的妖怪 ✨题目描述 露米娅作为宵暗的妖怪&#xff0c;非常喜欢吞噬黑暗。这天&#xff0c;她来到了一条路上&#xff0c;准备吞噬这条路上的黑暗。这条道路一共被分为n 部分&#xff0c;每个部分上的黑暗数量为ai 。露米娅每次可以任取 连续的 未被…

赚钱其实没有秘密,多琢磨一下不丢人

为什么学了很多知识还是挣不到钱&#xff1f; 挣不到钱&#xff0c;是因为你不够稀缺&#xff1b;挣钱太少&#xff0c;是因为你不懂杠杆&#xff0c;用杠杆撬动稀缺&#xff0c;个人价值自然水涨船高。 学富五车&#xff0c;为何财库依旧空空&#xff1f;怎样才能提高挣钱的…

在全志H616核桃派开发板上配置SSH远程终端方法详解

熟悉指令用户可以对已经联网的核桃派进行局域网SSH远程终端控制&#xff0c;方便使用自己的PC对核桃派远程进行各种指令操作。 普通用户&#xff08;默认&#xff09; 账号&#xff1a;pi ; 密码&#xff1a;pi管理员账户 账号&#xff1a;root ; 密码&#xff1a;root 在这之…

在Android Studio中使用谷歌Gemini代码助手

今天在做android开发的时候&#xff0c;一个项目使用到了gradle8.0&#xff0c;但是我的Android Studuio根本不支持&#xff0c;无可奈何只能从小蜜蜂版本升级了水母 | 2023.3.1版本&#xff0c;但突然发现AS已经集成了Gemini助手。 首先我们需要下载这个版本的&#xff1a; h…

2.5Bump Mapping 凹凸映射

一、Bump Mapping 介绍 我们想要在屏幕上绘制物体的细节&#xff0c;从尺度上讲&#xff0c;一个物体的细节分为&#xff1a;宏观、中观、微观宏观尺度中其特征会覆盖多个像素&#xff0c;中观尺度只覆盖几个像素&#xff0c;微观尺度的特征就会小于一个像素宏观尺度是由顶点或…

《java数据结构》--一篇解决二叉搜索树!!

&#x1f638;二叉搜索树的概念 二叉搜索树又名二叉排序树&#xff0c;一般具有以下性质&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉…