c++基础语法

文章目录

  • 前言
  • 命名空间
    • 命名空间的使用
  • 缺省参数
    • 缺省参数的使用
  • 函数重载
    • 函数重载的作用
    • 函数重载的使用
    • 函数重载原理
  • 引用
    • 引用的使用
    • 引用的使用场景
    • 引用和指针
  • extern C
  • inline
  • auto
  • 范围for
  • nullptr

前言

大家好我是jiantaoyab,这篇文章给大家带来的是c语言没有的一些特性之一,是c++的基础语法,对后面的学习有帮助,后面我将逐步编写类和对象、STL容器等C++笔记,欢迎大家关注我!

命名空间

当程序达到一个规模后,会不可避免的使用到相同的函数名和标识符导致冲突,可以使用namespace封装到一个命名空间中,一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

同一个工程中能存在相同的命名空间,相同名字的命名空间会合并到一起

作用域:变量的有效范围,从定义的起点开始,到定义变量之前最近的一对括号确定

命名空间的使用

//1.使用using使用命名空间成员之一
using jiantao::n;
//2.using namespace jiantao
//全部展开,失去封装的效果,不建议这样使用
namespace jiantao
{int n = 10;//可以嵌套使用namespace id{int b = 2;}
}int main()
{cout << n << endl; //using jiantao::n; 直接用cout << jiantao::n << endl; //一般的使用方法cout << jiantao::id::b << endl; return 0;
}

缺省参数

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

缺省参数的使用

注意点

  • 半缺省参数必须从右往左给,不能间隔给
  • 缺省参数不能在定义和声明中同时出现,建议在声明中写
  • 缺省值必须是全局变量或者是常量
void fun()
{cout << "fun()" << endl;
}//默认这里的参数会给值
void fun(int a ,int b=10,int c=20)
{cout << a << endl;cout << b << endl;cout << c << endl;}
int main()
{fun(1); fun(1,2);//传2的话b的值就是2
}

函数重载

函数重载是指在同一作用域内,声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,这组函数被称为重载函数

函数重载的作用

重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处

函数重载的使用

int add(int a, int b)
{return a + b;
}
double add(double a, double b)
{return a + b;
}
int main()
{add(1, 2);add(1.1, 1.2); //2个add构成重载return 0;
}

函数重载原理

Linux下,我定义了2个函数名字相同的函数,在gcc编译的时候,报错

image-20240309141027391

什么原因?

回忆一下一个程序编译链接的过程,在汇编的时候,会生成.o文件,.o文件是没有函数的地址的(声明和定义分开写),那么在链接的时候,会根据函数的名字去找地址,而在c语言中,不存在函数名字的修饰,根据函数的名字去符号表中找,假设在符号表中有Add(0x33123)和Add(0x332323),这在符号表中都冲突了,人家链接也不知道链接哪个

image-20240309143324511

而在c++中,存在函数名修饰规则,不同平台下不一样,在linux下大概为作用域+返回类型+函数名+参数列表,就能找到的函数的地址能链接上了

image-20240309143924393

重载大概的流程图

image-20240309144941774

我的知识有限,大家可以看看这篇 c++函数重载 里面有更详细的介绍

引用

引用不是新定义一个变量,而是给已经存在的变量起了一个别名,引用的变量和原来的变量共用一块内存空间

引用的使用

1.引用的类型和引用的实体必须的同类型的int a=10; int &b=a;2.引用在定义的时候必须初始化int &c=10 //error 引用的必须是一个对象const int a=10; int &b=a;//error a为常量
3.一旦一个引用被初始化指向一个对象,它就不能变为另一个对象的引用但一个对象可以有多个引用int a = 0;int& b = a;int& b = c; //ERRORint& c = a; //RIGHT
4.引用权限只能缩小,不能放大int a=10;const int &b=a;//✔ 权限缩小const int d = 10;int & f = d; //ERROR,这是权限的放大
5 临时变量本来是右值,是常量不能修改的double b = 1.1;int& i = d; //ERROR,存在类型转换,类型转换有临时变量const int& i2 = d //可以 

引用的使用场景

1.引用做参数 :提高效率,形参的改变能影响实参
int swap(int &x,int &y)
{}
使用引用传参,如果不改变参数的值,建议使用const引用2.引用做返回值:提高效率,修改返回变量(临时变量本来是右值,是常量不能修改的)
int& Add(int a,int b)
{int c=a+b; return c;
}
int main()
{int ret=Add(1,2);cout<<ret<<endl;
}

引用做返回值有一个重要的点,引用的这个返回对象在这个函数栈帧销毁的时候,还存在着才能使用引用返回。

int& Sub(int x, int y)
{int ret = x - y;return ret;
}int& f()
{int *p=(int *)malloc(4);return *p;//是可以的,p指向的空间还在return p;//error 指针p已经给销毁
}
int main()
{int& a = Sub(2, 1);
}  

image-20240309153633784

虽然编译通过了,但是上面的代码会存在非法访问的问题,Sub的返回值原来是临时变量,这里用了引用返回,那相当于int & ret = tmp,在调用完Sub后会回去访问ret的空间,假如Sub栈帧给销毁了,a所取到的值就是随机值,这里我们并没有马上使用这块空间才没报错。

image-20240309161456127

引用和指针

  • 引用在定义的时候必须初始化,指针不初始化也不报错
  • 引用一个对象之后就不能再引用别人对象,指针可以随意更改对象
  • 引用的大小是引用实体的大小,指针的大小是固定是4/8个字节
  • 引用不会开辟空间不占用内存
  • 引用加1是引用的实体加1,指针加1是向后偏移一个类型的大小

通过下面的汇编代码看出,引用和指针在使用的汇编指令是一样的

image-20240309164516106

extern C

大家有没有想过,如果我用c++写的程序,想去调用别人c写的库怎么去调用呢?

一会再回答这个问题,我们先来看看extern的用法。

extern是C语言中的一个关键字,一般用在变量名前或函数名前,作用是用来说明此变量/函数是在别处定义的,要在此处引用,在遇到此变量或函数的时候在其他文件中寻找其定义

extern int a;//声明变量a是在别的文件定义的,只是声明,没有分配内存
举个例子:   
比如我在test.cpp中 extern int num; extren void Print();
然后在fun.cpp 中  
int num = 1; //这里是定义变量  
void Print(){printf("Print()");} //这里是定义函数
这样子就能在test.cpp中使用这个num变量了 和 Print 这个函数了

想要在C++中调用c语言写的库,在vs2013下,需要执行下面操作

  1. 调试->属性->链接器 常规 ->附加库目录把库加上(Debug)

  2. 调试->属性->链接器 输入-> 附加依赖项 手动加入库的名字 xxx.lib

extern "C"
{//把头文件所在的目录包含#include "../../DS/DS/Stack.h" 
}

告诉C++编译器,extern “C”{}里面的函数是C编译器编译的,链接的时候用C的函数名规则去找,就可以链接上, 定义为extern的变量也会在外面去找

在C中调用c++写的库,要在cpp库中修改

//如果有__cplusplus 这个宏就用 extern "C" 替换 EXTRERN_C
#ifdef __cplusplus
#define EXTRERN_C extern "C" // C++静态库extern "C"告诉编译器以下函数按C的函数名修饰规则去处理
#else
#define EXTRERN_C  //这里走的是else 就是EXTRERN_C 什么都没有
#endifEXTRERN_C void StackInit(ST* ps); //运行后相当于 void StackInit(ST* ps)
EXTRERN_C void StackDestroy(ST* ps);
EXTRERN_C void StackPush(ST* ps, STDataType x);
EXTRERN_C void StackPop(ST* ps);
EXTRERN_C STDataType StackTop(ST* ps);
EXTRERN_C int StackSize(ST* ps);
EXTRERN_C bool StackEmpty(ST* ps);

inline

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销(使用内联函数在.o文件符号表不会生成函数的地址),内联函数提升程序运行的效率。

一般调用函数在汇编语言中是用call来调用的

image-20240312203723202

当把Add函数设置成内联函数后,再看看汇编,想要显示出效果需要在vs2013Debug下设置

image-20240312203904395

image-20240312204121429

image-20240312204047665

可以看到直接以函数的本体代替就像宏一样,但是会增加目标码的大小,会导致额外的换页行为,降低指令高速缓存装置的击中率。还有要注意的是inline只是对编译器的一个申请,不一定会采用

还有inline不建议声明的定义分离,分离会导致链接错误在小型、频繁调用的函数上,可以使用inline

小练习

A.使用inline关键字的函数会被编译器在调用处展开
B.头文件中可以包含inline函数的声明
C.可以在同一个项目的不同源文件内定义函数名相同但实现不同的inline函数

A.不一定,因为inline只是一种建议,需要看此函数是否能够成为内联函数

B. inline函数不支持声明和定义分离开,因为编译器一旦将一个函数作为内联函数处理,就会在调用位置展开,即该函数是没有地址的,也不能在其他源文件中调用,故一般都是直接在源文件中定义内联函数的

C.inline函数会在调用的地方展开,所以符号表中不会有inline函数的符号名,不存在链接冲突。

auto

自动推导类型:类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型 ,auto会忽略顶层的const,而底层const被保留(顶层const是指针本身是个 常量,底层const是指针指向的对象是一个常量)

int main()
{const int a = 10;auto b = a; // int cout << typeid(b).name() << endl;//不管原来对象是不是const 要想成为const的auto 要在 auto前加上const //例如 const auto b =a; 这样定义出来的b就是带const属性的int x = 1;auto a = x; //intauto&b = x; //int&auto*c = &x;//int *return 0;
}

auto不能使用的场景

1.不能作为函数的参数
void Add(auto a) //error 编译器无法对a的实际类型进行推导
auto b //error
2.不能用来声明数组
auto arr[]={1,2,3}; //error    

范围for

int main()
{int arr[] = { 1, 2, 3, 4, 5, 6, 7 };//范围for这个地方必须是数组名for (auto e: arr) //一个一个取arr的值放到e中{cout <<" "<< e; }cout << endl;//每个值加1for (auto&e : arr){e++;}cout << endl;for (auto e : arr){cout << " " << e;}cout << endl;}void printf_(int arr[]) for(auto e:arr)//error 数组传参的时候会退化为指针,不再是数组名字{cout<<e<<endl;}
}

nullptr

c++中用nullptr中比null好

void f(int)
{cout << "f(int)" << endl;
}
void f(int *)
{cout << "f(int *)" << endl;
}
int main()
{f(NULL);// NULL = 0 调用了f(int),本意是调用f(int*)f(nullptr);//调用f(int *)
}

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

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

相关文章

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——遗传算法(GA)

基于python语言&#xff0c;采用经典遗传算法&#xff08;GA&#xff09;对 需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整3. 求解结果4. 代码片段参考 往期优质资源 经过一年多的创作&#xff0c;目前已经成熟的…

Android 配置打包签名信息的两种方法

目录结构如下&#xff1a; 有2种方式&#xff1a; 第一种&#xff0c;直接配置&#xff1a; signingConfigs { debug { storeFile file("app/keystore.properties") storePassword "111111" keyAlias "key" keyPassword "111111" } …

2022-6 青少年软件编程(图形化) 等级考试试卷(一级)

第1题:【 单选题】 广场中有声控喷泉, 当声音的音量大于 60 的时候, 喷泉就会喷出水, 现在的音量为30,下列哪个选项可以让喷泉喷出水? ( ) A: B: C: D: 【正确答案】: B 【试题解析】 : 当前声音的音量为 30, 需要将声音增加到 60 以上就可以让喷泉喷出水, …

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的日常场景下的人脸检测系统(深度学习模型+PySide6界面+训练数据集+Python代码)

摘要&#xff1a;开发用于日常环境中的人脸识别系统对增强安全监测和提供定制化服务极为关键。本篇文章详细描述了运用深度学习技术开发人脸识别系统的全过程&#xff0c;并附上了完整的代码。该系统搭建在强大的YOLOv8算法之上&#xff0c;并通过与YOLOv7、YOLOv6、YOLOv5的性…

HTML5:七天学会基础动画网页12

“书接上回”继续对transition补充&#xff0c;在检查中找到ease后&#xff0c;鼠标放到ease前的紫色小方块就可以对运动曲线进行调整&#xff0c;这个曲线叫贝塞尔曲线&#xff0c;这里不做别的补充&#xff0c;不用了解&#xff0c;我们只要知道这个运动方式不只是有简单的匀…

.Net Core 中间件验签

文章目录 为什么是用中间件而不是筛选器&#xff1f;代码实现技术要点context.Request.EnableBuffering()指针问题 小结 为什么是用中间件而不是筛选器&#xff1f; 为什么要用中间件验签&#xff0c;而不是筛选器去验签? 1、根据上图我们可以看到&#xff0c;中间件在筛选器之…

MySQL--彻底解决Navicat备份时的报错

原文网址&#xff1a;MySQL--彻底解决Navicat备份时的报错_IT利刃出鞘的博客-CSDN博客 简介 本文介绍彻底解决Navicat备份时的报错。 正确的方法 见&#xff1a;MySQL命令--使用mysqldump导出导入数据库_IT利刃出鞘的博客-CSDN博客 错误的方法 方法1.转储SQL文件 这种方…

2.2 塑性力学——主应力、主方向、不变量

个人专栏—塑性力学 1.1 塑性力学基本概念 塑性力学基本概念 1.2 弹塑性材料的三杆桁架分析 弹塑性材料的三杆桁架分析 1.3 加载路径对桁架的影响 加载路径对桁架的影响 2.1 塑性力学——应力分析基本概念 应力分析基本概念 2.2 塑性力学——主应力、主方向、不变量 主应力、主…

【嵌入式——QT】标准对话框

【嵌入式——QT】标准对话框 文件对话框颜色对话框字体对话框输入对话框消息框代码示例 文件对话框 QFileDialog 常用静态函数 getOpenFileName&#xff1a;选择打开一个文件&#xff1b;getOpenFileNames&#xff1a;选择打开多个文件&#xff1b;getSaveFileName&#xff1…

【算法面试题】-07

小明找位置 题目描述 小朋友出操&#xff0c;按学号从小到大排成一列;小明来迟了&#xff0c;请你给小明出个主意&#xff0c;让他尽快找到他应该排的位置。 算法复杂度要求不高于nLog(n);学号为整数类型&#xff0c;队列规模<10000; 输入描述 1、第一行:输入已排成队列的…

浅淡 C++ 与 C++ 入门

我们知道&#xff0c;C语言是结构化和模块化的语言&#xff0c;适用于较小规模的程序。而当解决复杂问题&#xff0c;需要高度抽象和建模时&#xff0c;C语言则不合适&#xff0c;而C正是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的吸烟检测系统(深度学习+Python代码+PySide6界面+训练数据集)

摘要&#xff1a;本文详细说明了如何利用深度学习开发一个用于监测吸烟行为的系统&#xff0c;并分享了完整的代码实现。该系统采用了先进的YOLOv8算法&#xff0c;同时还使用YOLOv7、YOLOv6、YOLOv5算法&#xff0c;并对它们进行了性能比较&#xff0c;呈现了不同模型的性能指…

记一次特殊的渗透经历

起因 搞安全的小伙伴们应该知道&#xff0c;干我们这行老是会碰到一些奇奇怪怪的问题和需求&#xff0c;比如上次&#xff0c;某客户领导说让我给他找个会渗透的小伙子来&#xff0c;有个比较棘手的业务。我一听&#xff0c;心想&#xff1a;好嘛&#xff0c;这私活不就来了嘛…

MySQL 开发规范

优质博文&#xff1a;IT-BLOG-CN 一、设计原则 原则&#xff1a; SQL开发规范制定是基于良好的编码习惯和可读性&#xff1b; 目的&#xff1a; 消除冗余&#xff0c;数据简约&#xff0c;提高效率&#xff0c;提高安全&#xff1b; 【1】禁止在线上生产环境做数据库压力测试&…

视频监控管理系统EasyCVR平台设备增删改操作不生效是什么原因?

国标GB28181协议EasyCVR安防平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;平台支持7*24小时实时高清视频监控&#xff0c;能同时播放多路监控视频流&#xf…

数据结构——线性表顺序表示详解

目录 1.线性表的类型定义 2.基本操作 3.线性表的存储结构 4.补充 1.元素类型说明 2.数组定义​编辑 3.c语言的内存动态分配 4.c的动态存储分配 5.c中的参数传递 引用类型作参数 6.顺序表基本操作的实现 1.线性表的初始化 代码示例&#xff1a; 2.销毁线性表&…

什么是光伏气象站?—气象科普

光伏气象站&#xff0c;也称为光伏环境监测仪&#xff0c;是一种专门针对光伏发电站研发生产的环境监测系统。它主要利用太阳能电池板将太阳能转化为电能&#xff0c;并配备有气象监测设备以实时监测和记录气象数据。这些数据对于评估光伏电站的性能、效率和故障诊断至关重要&a…

SV-7045网络草坪音箱安装说明 景区园区背景音乐广播石头音箱

SV-7045网络草坪音箱安装说明 景区园区背景音乐广播石头音箱 在做室外公共广播/背景音乐系统时&#xff0c;对于草坪音箱的安装方法,大家可能不甚了解&#xff0c;所以将具体安装方法作简要说明。 音箱安装步骤如下&#xff1a; 1.测量草地音箱的底座尺寸大小&#xff0c;最…

Linux 多线程开发

第三章 Linux 多线程开发 3.1 线程3.1.2 线程操作3.1.2 线程属性 3.2 线程同步3.2.1 互斥量/锁3.2.2 死锁3.2.3 读写锁 3.3 生产者消费者模型3.3.1 条件变量3.3.2 信号量/灯 网络编程系列文章&#xff1a; 第1章 Linux系统编程入门&#xff08;上&#xff09; 第1章 Linux系统…

TSINGSEE青犀煤矿矿井视频监控与汇聚融合管理视频监管平台建设方案

一、背景需求 随着我国经济的飞速发展&#xff0c;煤炭作为我国的主要能源之一&#xff0c;其开采和利用的重要性不言而喻。然而&#xff0c;煤矿事故频发&#xff0c;不仅造成了巨大的人员伤亡和财产损失&#xff0c;也对社会产生了深远的负面影响。视频监控系统作为实现煤矿智…