当前位置: 首页 > news >正文

C++入门2

函数重载

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

比如下面的

int add(int x, int y)
{cout << "int add(int x ,int y)" << endl;return x + y;
}double add(double x, double y)
{cout << "double add(double x,double y)" << endl;return x + y;
}//参数个数不同void func()
{cout << "func()" << endl;}
void func(int x)
{cout << "func(int x)" << endl;
}//参数顺序不同void f(int x, char y)
{cout << "f(int x,char y)" << endl;
}void f(char y, int x)
{cout << "f(char y,int x)" << endl;
}
int main()
{add(1, 2);add(1.1, 1.2);func();func(2);f(1, 1.2);f(1.2, 1);return 0;
}

函数运行结果

值得注意的是,函数重载的定义是在同一个定义域里面的,如果在不同的作用域里面的话,就不算是函数的重载,下面的就不算是函数的重载

namespace LH
{int add(int x, int y){    cout << "int add(int x ,int y)" << endl;return x + y;}
}double add(double x, double y)
{cout << "double add(double x,double y)" << endl;return x + y;
}

 函数重载的一些注意事项

1.不同作用域里面的函数可以一样

namespace LH1
{void add(){cout << "LH1::add()" << endl;}
}
namespace LH2
{void add(){cout << "LH2::add()" << endl;}
}//using namespace LH1
//using namespace LH2
//加上这两句话在调用函数的时候虽然会冲突,但是依然不影响他们是重载的关系
int main()
{LH1::add();LH2::add();return 0;
}

 当函数是缺省参数的时候

//这两个函数虽然是重载函数,但是在调用的时候也会冲突
void f()
{cout << "f()" << endl;
}void f(int a = 10)
{cout << "f(int a)" << endl;
}

C++支持重载,C语言不支持

在C语言当中,是不支持重载的,但是在C++中,是支持重载的

这涉及到编译链接的过程,下面用一个图来解释

在上面的test.o文件里面,包含的有Add.h里面的东西,也就是函数的申名,在链接的过程中,有了函数的申明,编译器会找函数的定义,也就是在.CPP文件去找函数的地址(这里函数的地址实际上就是函数的语句)

由于C语言和C++找函数的方式不同

C语言用的是函数名去找,而C++是用被修饰的函数名字去找(也就是包含函数里面的参数),C语言用函数的名字去找,有多个函数名就会报错,但是C++不会

引用

1. 引用在定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体

引用实际上就是给变量取别名,对别名进行操作也会引起自身的变化

int main()
{//整形变量的别名int a=10;int&b=a;    //给a取一个别名,相当于给a取一个外号//指针变量的别名int x = 0;int* p1 = &x;int*& p2 = p1;retrun 0;}

权限的平移,缩小,放大

// 权限的平移,可以
int x = 0;
int& y = x;
y++;
//权限的缩小,可以
int x=0;
const int& z = x;
z++;       // 不可以// 权限的方法// m只读// n变成我的别名,n的权限是可读可写// 权限的放大,不可以const int m = 0;// int& n = m;const int& n = m;// 可以,不是权限的放大// m拷贝的给p,p的修改不影响mint p = m;// 权限的放大// p1可以修改 *p1不可以,const修饰是的*p1const int* p1 = &m;// p1++;// int* p2 = p1;const int* p2 = p1;// 权限的缩小int* p3 = &x;const int* p4 = p3;

引用作为函数参数

引用也可作为函数参数来代替指针的一些操作(形参是实参的引用)

void Swap(int& x, int& y)
{int temp = x;x = y;y = temp;
}int main()
{int a = 10;int b = 20;Swap(a, b);cout << "a=" << a << endl;cout << "b=" << b << endl;return 0;
}

输出结果

传值和传引用效率的比较

值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直
接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效
率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}int main()
{TestRefAndValue();return 0;
}

运行结果

通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大 

引用和指针的区别

语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

int main()
{int a = 10;int& ra = a;cout << "&a = " << &a << endl;cout << "&ra = " << &ra << endl;return 0;}

运行结果

从结果上面来看,引用别的变量是和别的变量用同一块空间

但是在从底层来看,引用和指针一样,都是用指针的方式实现的

int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}

引用和指针的不同点:
1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用在定义时必须初始化,指针没有要求
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
4. 没有NULL引用,但有NULL指针
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全 

内联函数

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调
用建立栈帧的开销,内联函数提升程序运行的效率

上面的call是调用函数地址的意思

内联函数的特性 

1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会
用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
行效率。
2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建
议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不
是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性

3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址
了,链接就会找不到

// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{
f(10);
return 0;
}
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl
f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

auto关键字

auto关键字是根据等式左边的数据类型来确定变量的类型的

auto a=1;  //右边是整形,左边自动得出a是整形变量

这个关键字现阶段还没有什么意义,但是等到等式右边的变量是一个很长的类型的时候,就会很有意义

std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange",
"橙子" },
 {"pear","梨"} };
//std::map<std::string, std::string>::iterator it = m.begin();

 //换成下面的这个

auto it=m.begin();

 std::map<std::string, std::string>::iterator 是一个类型,但是该类型太长了,特别容
易写错。

可以通过typedef给类型取别名,比如

#include <string>
#include <map>
typedef std::map<std::string, std::string> Map;
int main()
{
Map m{ { "apple", "苹果" },{ "orange", "橙子" }, {"pear","梨"} };

Map::iterator it = m.begin();
while (it != m.end())
{
//....
}
return 0;
}

 使用typedef给类型取别名确实可以简化代码,但是typedef有会遇到新的难题

typedef char* pstring;
int main()
{
const pstring p1;   // 编译成功还是失败?  失败 需要给值
const pstring* p2;  // 编译成功还是失败?  成功
return 0;
}

8.2 auto简介
 

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的
是一直没有人去使用它,大家可思考下为什么?
C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一
个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

int TestAuto()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = TestAuto();
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
return 0;
}

 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto
的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编
译期会将auto替换为变量实际的类型。

 auto的使用细则

1. auto与指针和引用结合起来使用
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须
加&

int x = 10;
  auto a = &x;
  auto* b = &x;    //如果有*,右边必须是一个指针变量
  auto& c = x;

 在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译
器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

void TestAuto()
{
  auto a = 1, b = 2;
  auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

 

auto不能推导的场景 

 1,auto不能作为函数的参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

auto不能直接用来声明数组

void TestAuto()
{
  int a[] = {1,2,3};
  auto b[] = {4,5,6};
}

 遍历数组

auto还可以用来遍历数组(范围for)

oid TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)              //不加&是不会改变数组里面的值的e *= 2;
for(auto e : array)cout << e << " ";
return 0;
}
void TestFor(int array[])
{for(auto& e : array)cout<< e <<endl;
}

范围for的使用条件

1. for循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供
begin和end的方法,begin和end就是for循环迭代的范围。
注意:以下代码就有问题,因为for的范围不确定

void TestFor(int array[])
{
  for(auto& e : array)
    cout<< e <<endl;

}

空指针

在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现
不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下
方式对其进行初始化: 

void TestPtr()
{
int* p1 = NULL;
int* p2 = 0;
// ……
}

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL  0
#else
#define NULL  ((void *)0)
#endif
#endif

可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何
种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如

void f(int)
{
cout<<"f(int)"<<endl;
}
void f(int*)
{
cout<<"f(int*)"<<endl;
}
int main()
{
f(0);                 输出:第一个
f(NULL);                输出:第一个f((int*)NULL);            输出:第二个
return 0;
}

 程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的
初衷相悖。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器
默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void
*)0。

注意:
1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入
的。
2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

相关文章:

C++入门2

函数重载 函数重载&#xff1a;是函数的一种特殊情况&#xff0c;C允许在同一作用域中声明几个功能类似的同名函数&#xff0c;这 些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同&#xff0c;常用来处理实现功能类似数据类型 不同的问题 比如下面的 int add(int x…...

在Nestjs使用mysql和typeorm

1. 创建项目 nest new nest-mysql-test 2. 添加config 安装 nestjs/config 包 pnpm i --save nestjs/config 添加 .env 文件 DATABASE_HOSTlocalhost DATABASE_PORT3306 DATABASE_USERNAMEroot DATABASE_PASSWORD123456 DATABASE_DBdbtest 创建 config/database.config.…...

【数据库】MySql深度分页SQL查询优化

问题描述 mysql中&#xff0c;使用limitoffset实现分页难免会遇到深度分页问题&#xff0c;即页码数越大&#xff0c;性能越差。 select * from student order by id limit 200000,10;如上语句&#xff0c;其实我们希望查询第20000页的10条数据&#xff0c;实际执行会发现耗时…...

黑马Java零基础视频教程精华部分_14_正则表达式

系列文章目录 文章目录 系列文章目录一、先爽一下正则表达式不使用正则的情况下使用正则的情况下 二、正则表达式的作用三、正则表达式具体表达1、规则2、字符类示例3、预定义字符示例首先学习转义字符 示例练习 四、基本练习1、快捷方法&#xff1a;2、验证手机号3、验证座机电…...

20240812 每日AI必读资讯

黑匣子被打开了&#xff01;能玩的Transformer可视化解释工具&#xff1a;Transformer Explainer - 佐治亚理工学院和 IBM 研究院开发一款基于 web 的开源交互式可视化工具「Transformer Explainer」&#xff0c;帮助非专业人士了解 Transformer 的高级模型结构和低级数学运算…...

C++ 项目中的类框架

/* * 类调用框架 */ /* CameraApp.h */ class CameraApp { public: CameraApp(); ~CameraApp(); int Init(void); int UnInit(void); public: XnetNode m_xnode_thd; XcamServer m_xcam_thd; }; /* CameraApp.cpp */ CameraApp::CameraApp(): m_…...

【Python随笔】比PyQt5更先进的pyside6安装和使用方法

最近因为自研日常开发工具的需求&#xff0c;决定重新拾起PyQt5之类的桌面工具开发技术栈&#xff0c;为啥选用PyQt&#xff0c;一是因为笔者比较精通python&#xff0c;二是因为不需要在外观上做什么特别的东西。经过一番调研&#xff0c;发现当前的PyQt5版本已经过时&#xf…...

如何给 VMware Workstation 虚拟机配置代理

文章目录 步骤一&#xff1a;检查虚拟机网络设置步骤二&#xff1a;获取代理服务器 IP 地址步骤三&#xff1a;配置虚拟机的代理设置步骤四&#xff1a;验证代理配置总结 在使用 VMware Workstation 虚拟机时&#xff0c;有时候我们需要通过代理服务器访问外部网络资源。本文将…...

前端路由VueRouter总结

简介&#xff1a; Vue路由vue-router是官方的路由插件&#xff0c;能够轻松的管理 SPA 项目中组件的切换。Vue的单页面应用是基于路由和组件的&#xff0c;路由用于设定访问路径&#xff0c;并将路径和组件映射起来vue-router 目前有 3.x 的版本和 4.x 的版本&#xff0c;vue-…...

基于SpringBoot+Vue的铁路订票管理系统(带1w+文档)

基于SpringBootVue的铁路订票管理系统(带1w文档) 基于SpringBootVue的铁路订票管理系统(带1w文档) 铁路订票管理工作向来都是社会上不可或缺的一部分&#xff0c;然而多年以来人们大都习惯使用传统方法&#xff0c;即人工来完成铁路订票的管理&#xff0c;但是这种方法存在着工…...

Firefox滚动条在Win10和Win11下表现不一致问题?

文章目录 前言总结解决方法 前言 最近在写页面的时候发现一个非常有意思的事。Firefox滚动条在Win10和Win11下表现居然不一致。在网上几经查找资料&#xff0c; 终于找到原因所在。总结成下面的文章&#xff0c;加深印象也防止下次遇到。 总结 参考文章&#xff1a; Firefox…...

vue3 组件传参

import {reactive,defineProps,onMounted,ref} from vue const props defineProps({ projectInfo: { type: Object, default: () > { return {}; } } }); console.log("&#x1f680; ~ 审核详情项目概述:", props.projectInfo) <Detail v-if"isReady…...

unity自动添加头部注释脚本

unity自动添加头部注释脚本&#xff0c;放在Assets目录自动生效 public class ScriptCreateInit : UnityEditor.AssetModificationProcessor {private static void OnWillCreateAsset(string path){path path.Replace(".meta", "");if (path.EndsWith(&qu…...

Raw格式化后文件能恢复吗 电脑磁盘格式化后如何恢复数据 硬盘格式变成了raw怎么恢复

硬盘、U盘等移动存储设备在存储数据文件上是非常方便的&#xff0c;不过在使用过程中也会因为操作、或者本身设备问题&#xff0c;导致存储设备出现各种各样的问题。较为常见的问题就是存储设备格式化、存储设备格式变为Raw格式等。今天要给大家分享的是有关Raw格式化的相关内容…...

Android targetSdkVersion改成33遇到的坑

targetSdkVersion 改成 33 &#xff0c;遇到一些坑。 需要注意的地方&#xff1a; 修改 targetSdkVersion 为 33。AndroidManifest.xml 里添加 android:exported“true”升级 Gradle 版本。升级第三方库。 修改 app 的 build.gradle &#xff0c; android {compileSdkVersi…...

1985-2023年中国城市统计年鉴(PDF+EXCEL)

1985-2023年中国城市统计年鉴 1、时间&#xff1a;1985-2023年 2、格式&#xff1a;1985-2023年PDF版本&#xff0c;1993-2023年excel格式 3、说明&#xff1a;中国城市统计年鉴收录了全国各级城市社会经济发展等方面的主要统计数据&#xff0c;数据来源于各城市的相关部门。…...

从AI小白到大神的7个细节:让你开窍逆袭

在当今科技界&#xff0c;人工智能无疑是最炙手可热的话题。然而&#xff0c;这个领域充斥着专业术语&#xff0c;使得理解每次技术革新的具体内容变得颇具挑战性。 为了帮助读者更好地把握时代脉搏&#xff0c;本文整理了一系列常见的人工智能&#xff08;AI&#xff09;术语…...

AIxBoard部署BLIP模型进行图文问答

一、AIxBoard简介 AIxBoard&#xff08;X板&#xff09;是一款IA架构的人工智能嵌入式开发板&#xff0c;体积小巧功能强大&#xff0c;可让您在图像分类、目标检测、分割和语音处理等应用中并行运行多个神经网络。它是一款面向专业创客、开发者的功能强大的小型计算机&#xf…...

小白零基础学数学建模应用系列(一):探索自由下落模型——以“坠落的硬币”为例

在数学建模竞赛中&#xff0c;选择一个易于理解且有趣的物理现象作为研究对象&#xff0c;往往能够使模型的构建和分析更具吸引力和说服力。本篇文章将以“坠落的硬币”这一经典的自由下落问题为例&#xff0c;探讨如何通过建立物理模型来验证或推翻常见的物理误解&#xff0c;…...

linux主机间免密登录

目录 原理&#xff1a; 相关命令&#xff1a; 一&#xff0c;执行命令 cd ~/.ssh/ &#xff0c;进入目录 二&#xff0c;如果没有公钥和秘钥文件&#xff0c;则执行命令来生成 三&#xff0c;负责公钥给远端端服务器命令 四&#xff0c;实操 场景一&#xff0c;localhos…...

【海思SS626 | VB】关于 视频缓存池 的理解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

RCE漏洞及绕过

目录 1、RCE概述 &#xff08;1&#xff09;命令执行函数 &#xff08;2&#xff09;代码执行函数 2、回调后门 3、eval和assert 限制字符长度绕过 &#xff08;1&#xff09;反引号或exec &#xff08;2&#xff09;file_put_contents写入文件 &#xff08;3&#xff…...

非对称加密算法-ECDHE

目录 1. ECDHE算法简介 密钥交换算法的重要性 ECDHE算法的基本原理 2. ECDHE与RSA算法的比较 RSA算法 ECDHE算法 比较 图形结合 2. HTTPS中的密钥交换 RSA算法的局限性 前向安全性的概念 图形结合 3. 离散对数问题 离散对数的定义 离散对数在密码学中的应用 图…...

10分钟学会Docker的安装和使用

前言 在现代软件开发中&#xff0c;Docker作为一种轻量级的容器化技术&#xff0c;已成为开发者必备的工具之一。本文将带您在10分钟内快速掌握Docker的安装和基本使用方法。 1. Docker是什么&#xff1f; Docker是一种开源的容器化平台&#xff0c;它通过将应用程序及其所有…...

江科大/江协科技 STM32学习笔记P20

文章目录 编码器接口测速定时器有关的库函数Encoder.cmain.c 编码器接口测速 编码器接口的初始化&#xff0c;第一步&#xff0c;RCC开启时钟&#xff0c;开启GPIO和定时器的时钟&#xff0c;第二步&#xff0c;配置GPIO&#xff0c;这里把PA6和PA7配置成输入模式&#xff0c;第…...

CSS 实现两边固定宽,中间自适应

0. **Flexbox 实现**&#xff1a; css复制代码.container { display: flex; } ​ .fixed { width: 200px; /* 两边固定宽度 */ } ​ .flexible { flex: 1; /* 中间自适应 */ } html复制代码<div class…...

C#图片批量下载Demo

目录 效果 项目 代码 下载 效果 C#图片批量下载 项目 代码 using Aspose.Cells; using NLog; using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.…...

部署Springboot + Vue 项目到远程服务器Windows10系统的详细配置

远程服务器操作系统为Windows系统&#xff0c;Java程序环境&#xff0c;Maven环境都安装有&#xff0c;Mysql ,Redis等都有的前提下 1. mysql数据库导入&#xff0c;非常简单很好操作&#xff0c;这里省略。。比如用HeidiSql 或者Navicat 工具导入数据库 2. 后端javaSpringb…...

智驭灌区,科技领航—— 高效灌区信息化系统管理平台

在水资源日益珍贵的今天&#xff0c;传统灌区的粗放式管理模式已难以满足现代农业的发展需求。我们自豪地推出——灌区信息化系统管理平台&#xff0c;以科技赋能水利&#xff0c;引领灌溉管理进入智能化、精细化新时代。 【智能决策&#xff0c;精准灌溉】 告别传统灌溉的盲目…...

下载免费设计素材,有这7个网站就够了

7个免费设计素材网站&#xff0c;这些网站提供了大量的免费资源&#xff0c;包括图片、字体、图标、模板等&#xff0c;涵盖了多种风格和主题&#xff0c;能够满足不同设计师和创作者的需求。无论是用于个人项目还是商业用途&#xff0c;这些网站都能给你提供丰富的选择&#x…...