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

C++入门学习

目录

C++入门

1.namespace命名空间

2.C++的输入与输出

3.缺省参数

4.函数重载

5.引用

5.1引用和指针的关系

6.inline函数

7.nullptr


C++入门

C++兼容C语言的大多数语法,在C语言中我们的第一个程序是这样写的

#include<stdio.h> int main() { printf("hello world"); return 0; }

在C++中这样的语法仍然是可以运行的,但是在C++中我们这样写,使用cout进行输出,这样写的好处是我们不需要写输出的占位符类型,会自动识别类型进行输出,所以在自定义类型的输出上会方便很多

#include<iostream> using namespace std; int main() { cout << "hello world" << endl; return 0; }

1.namespace命名空间

在C++中有四个域,全局域,局部域,命名空间域,类域

命名空间域就是namespace,在这里定义的变量以及函数和其他域可以很好地分离开,避免命名冲突等问题,而在正常情况下,编译器查找一个变量时,默认只会在局部域和全局域进行查找,所以如果要使用命名空间内部的变量,我们有三种使用方法

指定命名空间访问:命名空间::

将某个成员展开:using 命名空间::变量;

展开整个命名空间:using namespace 命名空间;

第一种方法是最推荐使用的,对于命名空间内部的变量以及函数,直接指定命名空间去访问

例如我们现在将一块空间命名为test,在其中定义x以及一个add函数,在输出的时候,如果没有指定命名空间,那么只在全局域以及局部域去查找变量,所以第一个x会输出10,第二个x因为指定了test这个命名空间,那么会输出1,add函数因为在命名空间域内,所以也需要指定命名空间访问

#include<iostream> using namespace std; namespace test { int x = 1; int add(int x, int y) { return x + y; } } int main() { int x = 10; cout << x << endl; cout << test::x << endl; cout << test::add(1, 2) << endl; return 0; }

2.C++的输入与输出

C++的标准库都放在一个叫做std的命名空间中,我们再练习写代码的时候,可以直接将std展开,这样使用内部函数就很方便

头文件<iostream>,定义了标准的输入和输出对象

std::cin是istream类的对象,主要面向窄字符的标准输入

std::cout是ostream类的对象,主要面对窄字符的标准输出

std::endl相当于一个换行符的作用,并刷新缓存区

<<是流插入运算符,>>是流提取运算符

使用C++在输入输出时会更加方便,不需要手动指定输入输出的格式,C++的输入输出可以自动识别变量类型,且更好地支持定义类型对象的输入和输出

#include<iostream> using namespace std; int main() { int a = 0; int b = 0; cin >> a >> b; cout << a << b << endl; return 0; }

3.缺省参数

我们在定义函数时,可以将某些参数指定一个缺省值,表示如果使用函数时没有给该参数手动赋值,那么就会调用这个缺省值进行操作

缺省分为全缺省和半缺省,全缺省就是全部变量都给上缺省值,半缺省就是只给一部分变量给缺省值,另一部分仍然需要使用函数时手动赋值

C++规定半缺省的缺省参数必须从右往左依次给,不可以跳跃,同样的在给实参的时候也必须从左往右给,不可以跳跃给实参,这样才不会出现歧义,不知道哪个实参赋值给了哪个形参

例如下面的代码,从右往左给了两个形参缺省值,在使用函数时,从左往右给了三个实参,既然有了实参,那么变量z就不会使用缺省值10,而是使用给的实参3

#include<iostream> using namespace std; int add(int x, int y, int z = 10, int k = 20) { return x + y + z + k; } int main() { cout << add(1, 2, 3) << endl; return 0; }

注意一点,如果函数的声明和定义是分离的话,缺省值只能给在函数声明的位置

4.函数重载

C++允许同一个作用域中出现同名函数,只要这些函数的形参不同就可以构成重载,不管是参数个数不同还是参数类型不同,表现出了多态行为

例如以下add函数,都构成函数重载,在使用时会根据传入参数的类型个数顺序等不同,自动调用对应的函数,使用起来比较方便

int add(int x, int y) { return x + y; } double add(double x, double y) { return x + y; } int add(int x, int y, int z) { return x + y + z; } double add(int x, double y) { return x + y; }

5.引用

引用与C语言经常使用的指针的作用基本是一致的

引用的写法:类型& = 引用对象

例如我们定义一个整型变量b,使用c和d引用它,相当于给b取了别名,在使用c和d的时候本质上就是在使用b这个变量,所以直接对c和d修改值,可以更改b的值

注意一个别名只能引用一个实体变量,但是一个变量可以有多个引用

所以这里将d赋值为y,是将y的值赋值给它,而不是d改变了引用对象

引用的使用本质是为了简化程序,避开复杂的指针,因为取别名更容易理解,例如张三,它的外号叫小张,我们说小张在写代码,本质上就是张三这个人在写代码,直接对我们需要使用的那个变量进行操作,比用指针取地址操作更加简便

int b = 10; int& c = b; int& d = b; cout << b << endl; cout << c << endl; cout << d << endl; int y = 20; d = y;//只能引用一个实体,所以这里d依旧是b的别名 //将值更改为20 cout << b << endl; cout << c << endl; cout << d << endl;

回想一下之前使用C语言写栈,调用初始化函数和入栈函数等操作时,我们需要传入栈的地址,也就是&stack去操作,但是如果我们将传入的形参改为引用,相当于对这个栈取别名,可以直接用这个别名进行操作,而且代码可读性更高

例如下面这段代码,定义了一个叫st的栈,然后有三个函数,原本我们在函数形参这一块使用的是指针类型的传入,然后用指针去操作栈内的变量,现在直接使用引用的操作,相当于直接对栈本身进行操作,函数写起来更简便,而且使用函数时很直观的知道是在对栈进行什么操作,可以直接传入栈,而不是传入一个地址

typedef int StackDataTpye; struct StackNode { StackDataTpye* arr; int top;//栈顶 int space;//空间大小 }; typedef struct StackNode SN; void StackInit(SN& stack) { //初始化栈 stack.arr = (StackDataTpye*)malloc(2 * sizeof(StackDataTpye)); //初始先申请两个空间 if (stack.arr == NULL) { perror("malloc"); return; } //将栈顶置为0 //空间大小置为2 stack.top = 0; stack.space = 2; } void StackPush(SN& st, StackDataTpye x) { assert(st.arr != nullptr); if (st.top == st.space) { //如果栈顶到达空间上限时 //对数组进行扩容 StackDataTpye* p1 = (StackDataTpye*)realloc(st.arr, 2 * (st.space) * sizeof(StackDataTpye)); if (p1 == NULL) { perror("realloc"); return; } st.arr = p1; st.space *= 2;//进行二倍扩容 } //进行入栈操作,top++ st.arr[st.top] = x; st.top++; } void PrintStack(SN& st) { //遍历栈进行打印 assert(st.arr != nullptr); for (int i = 0; i < st.top; i++) { printf("%d ", st.arr[i]); } printf("\n"); } SN st; StackInit(st); StackPush(st, 1); StackPush(st, 2); StackPush(st, 3); PrintStack(st);

注意一下const引用的操作,对于一些临时对象和本身就是const修饰的变量的引用,需要使用const引用,因为引用可以进行权限的缩小,但是不可以进行权限的放大

例如对于const修饰的变量a,用int&进行引用,是一种权限的放大,本来a的值是不允许修改的,但是c引用a之后,对a的值有修改的风险,所以不可以这样写,但是权限的缩小是可以的,我们可以直接修改bb的值为20,注意这里的const作用是防止通过该引用修改bb的值,而不是锁定了dd的值为bb修改前的10,所以在bb修改为20之后,dd的值也是20,只不过不能通过直接更改dd的值来修改bb,这样写是会报错的

看第三个例子,yy*3是一个临时对象,而C++中临时对象具有常性,是不可以被修改的,所以如果用int&直接去引用,触发了权限放大,所以对x++操作时,相当于对一个常量进行修改,会报错

const int a = 1; int& c = a; //这样是会报错的,因为const修饰的a值不可更改 //int& c是对权限的放大,所以不对 //可以进行权限的缩小,但是不能进行权限的放大 int bb = 10; const int& dd = bb; //这样进行权限缩小的引用是可以的 bb = 20; dd = 30; //这样是不能修改的,因为dd是const修饰 //所以当bb用别名dd时不能修改 //但是仍然可以通过使用bb变量名修改bb本身的值 int yy=10; int& xx=yy*3; xx++; //在C++中,一个通过表达式产生的值是需要临时拷贝的,叫做临时对象 //这个拷贝出来的值具有常性,不可以更改 //相当于对于yy*3的拷贝值,使用了const修饰 //此时用xx给他取别名,没有用const触发了权限放大 //所以会产生报错,因为拷贝值具有常性

5.1引用和指针的关系

引用作为变量的别名,不开辟空间,指针要存储变量的地址,需要开辟一块空间存储

引用在定义时必须初始化,指针只是建议初始化

引用在初始化引用一个对象之后,就不能更改了,而指针可以不断改变指向的对象

引用是直接访问引用的对象,而指针解引用之后才是指向的对象

引用结果的大小为引用对象的大小,指针的大小取决于环境是32位还是64位

指针容易出现空指针和野指针的问题,引用相对安全一点

6.inline函数

C++设计inline函数的目的就是替代C语言的宏函数,因为宏函数在预处理展开替换时,会由于优先级的问题导致结果不正确,因为宏函数是直接进行替换,而且不方便进行调试

对于内联函数来说,不支持声明与定义分开,直接将定义写在需要使用他的文件下,因为inline函数使用时,是一种替换,不会产生链接的操作,使用call去开辟函数栈帧,所以如果分离声明与定义,会由于找不到链接地址而报错,inline函数的使用只是对编译器的建议,递归函数以及代码量大的函数即使加上inline,编译器仍然不会直接展开函数,而是call调用,代码量小且使用频繁的函数可以用inline函数

如果想知道内联函数在运行时是否展开还是直接call调用,可通过调试,打开反汇编,运行到该函数的地方时,如果使用call说明没有展开,反之则进行了展开,例如以下函数,虽然是内联函数,但是实际使用时还是再用call,所以inline对于编译器只是一个建议

7.nullptr

在C语言中我们用NULL表示指针为空,表示无类型指针void*的常量,但是在C++中,NULL可能被定义为常量0,所以如果用NULL作为函数实参传入时,如果有两个函数,一个需要传入一个指针,另一个需要传入整型变量,但是此时我们用NULL作为实参,肯定是希望调用第一个函数,但是由于NULL可能被解释为0,那么就会调用第二个函数,背离了预期

所以在C++引入了nullptr,它是一个特殊关键字,可以转换为任意其他类型的指针类型,所以使用nullptr就可以避免这种问题,因为nullptr只能被隐式转换为指针类型,而无法被转换成整数类型

http://www.jsqmd.com/news/522633/

相关文章:

  • 3月逛解放碑,这几家好吃的火锅值得一试,火锅找哪家煊火锅显著提升服务 - 品牌推荐师
  • S-Function(二)——参数处理与错误调试
  • MOEA-D算法实战:如何用权重求和法快速找到帕累托最优解(附Python代码)
  • 盘点2026年水溶肥市场趋势,靠谱供应商中微量元素含量排行 - myqiye
  • 玩转T型三电平并网控制:手撕C代码实现工业级控制方案
  • 第十九届全国大学生信息安全竞赛(创新实践能力赛)暨第三届“长城杯”网数智安全大赛(防护赛)半决赛圆满举办
  • 腾讯CodeBuddy.ai实战:5分钟用AI生成可部署的五子棋游戏(附房间系统源码)
  • 上海大众搬家公司怎么样,2026年居民搬家公司推荐别错过 - mypinpai
  • Windows和Ubuntu双系统下GitHub访问慢?3分钟搞定Hosts配置(附最新IP查询方法)
  • 玩转Abaqus插件开发】让裂缝在模型里自由生长
  • FPGA新手必看:用Vivado+ModelSim实现ADC128S022的SPI信号采集(附完整代码)
  • Claude Code、OpenCode、OpenClaw:插件这么多,选哪个?
  • HPatches数据集终极指南:计算机视觉特征匹配的完整实践手册
  • 【实战解析】从Focal Loss到CEFL2:用PyTorch攻克表情分类中的类别不平衡难题
  • CLIP-GmP-ViT-L-14效果展示:艺术画作→风格描述/流派标签/创作年代预测结果
  • 告别原生Swagger!Ruoyi-Cloud项目接入Knife4j的5个关键步骤与常见问题解决
  • FUTURE POLICE语音解构效果展示:多方言与嘈杂环境下的识别精度对比
  • 基于Comsol仿真模型的锂枝晶生长过程研究:形貌、温度场耦合、应力场、浓度场及电势场的综合模...
  • 选对起点很关键!2026年五家优质儿童英语培训机构盘点 - 品牌2025
  • 深拷贝与浅拷贝
  • 再互动剖析哈尔滨啤酒扫码领红包80%中奖率背后的三层逻辑 - 品牌智鉴榜
  • 跨平台协同:AMESim与Matlab/Simulink联合仿真环境搭建与实战指南
  • 用GraphRAG 2.0.0+阿里云API,给你的本地文档库做个“知识大脑”(附四种查询方法对比)
  • 南方电网电费监控Home Assistant集成:5分钟实现智能用电管理
  • 深度解析安科士800G OSFP 2FR4光模块,解锁高速互联核心技术
  • 大模型学习day1:prompt engneering
  • 别只盯着80端口:Tomato靶机渗透中那些容易被忽略的‘边路’突破口(2211端口与日志审计)
  • refine 命令:增量扩展 CLI 覆盖面的正确姿势
  • 2026 企业网盘选型指南:大型企业只需关注这 5 款主流方案的实测差异
  • QGIS天地图插件进阶玩法:多Key轮换+省级节点加速配置指南