C++学习记录——일 C++入门(1)

news2025/1/13 13:41:33

C++入门(1)


文章目录

  • C++入门(1)
  • 一、C++关键字
  • 二、C++第一个程序
  • 三、命名空间
      • 1、域作用限定符
      • 2、了解命名空间
      • 3、命名空间的使用
  • 四、C++输入输出
  • 五、缺省参数
  • 六、函数重载
  • 七、引用
      • 1、引用符号
      • 2、引用的部分使用场景


一、C++关键字

在这里插入图片描述

关键字有98个,在之后的文章中再逐个写出来。

二、C++第一个程序

#include <iostream>
using namespace std;

int main()
{
	cout << "hello world" << endl;
	return 0;
}

不同于printf,c++用cout,而endl也就是’\n’的意思,<<则是流输入。去掉 << endl就不是自动换行了。

三、命名空间

1、域作用限定符

C++兼容C的所有语法,我们可以直接用。
命名空间是什么?有什么作用?首先可以看到的是,这是一块空间。但这个空间为何叫命名?我们实际写代码时,如果多人写代码,然后引用到其中一个文件来,就会出现一个问题,如果有两个人创建的变量名一样,那么程序就出错了,所以C语言就有这样一个缺陷。C++为了解决这种冲突,就出现了命名空间这个语法。
我们先一点点来理解命名空间
C语言中有全局域和局部域 ,有了全局变量后,在一个函数里再加入一个同名局部变量,那么在函数里打印出来的值就是局部变量的值。看代码

int a = 0;

void f1()
{
	int a = 1;
}

void f2()
{
	int a = 2;
	printf("%d\n", a);
}

int main()
{
	printf("%d\n", a);
	f2();
	return 0;
}

这时候的结果就是0和2.如果我们在f2函数里也想打印全局变量怎么办?当然,在int a = 2之前就printf一下即可,不过这里用的不是这个方法。我们要用到一个域作用限定符。

void f2()
{
	int a = 2;
	printf("%d\n", a);
	printf("%d\n", ::a);
}

::这个域作用限定符前面有空格就表示在全局范围寻找,如果全局没有相应的变量名,就会出错。

在这里插入图片描述

2、了解命名空间

现在开始多个文件使用,创建两个.h文件。写入一些代码,让这些代码有重复命名的部分

struct Node
{
	struct Node* next;
	int val;
};

struct Queue
{
	struct Node* head;
	struct Node* tail;
};
struct Node
{
	struct Node* next;
	struct Node* prev;
	int val;
};

yy.h和dd.h文件。这时候把这两个都引进来。
在这里插入图片描述

这里会出现重定义的错误。在C语言里,这样只能改名;但是C++可以用命名空间解决。在刚才的域中,一个域里不能出现两个同名变量,f2函数里正常的输出a,就输出局部变量的值,而输出全局变量的值需要加上域作用限定符。这里的命名空间相当于加一个域,把文件所有的代码都套上一个空间,那么两个文件代码虽然相同,但在不同空间里,也就互不影响。所以能够看出命名空间影响使用。不过命名空间不影响生命周期,全局变量还是全局变量,局部变量还是局部变量。

namespace dd
{
	struct Node
	{
		struct Node* next;
		struct Node* prev;
		int val;
	};
}

像这样,包进命名空间里再引用就不会出问题了。但是问题还没结束。现在在cpp文件里建立一个变量,用struct Node类型,这时候程序还是出错了。虽然有了命名空间,但程序在搜索struct Node的声明时不会在命名空间里面找,而是在全局域和局部域里面找,所以还是报错了。如何解决?前面我们提到了域作用限定符,::前面为空格时是指定全局域里面找,现在加上命名空间,struct dd :: Node,struct yy :: Node,两个Node变量就不冲突了。至于不放在struct前面,是因为同名冲突的是Node,而不是struct,比如我还可以声明struct snode,那么查找的也就是snode这个标识。

#include "dd.h"
#include "yy.h"

int main()
{
	struct yy::Node m;
	struct dd::Node n;
	return 0;
}

以及想要用同样名字的变量,也要放进命名空间里才可。在yy空间里再声明一个num的整型,那么外面就要用yy::num才能操作它。
如果命名空间也重名了怎么办?对于重名的空间,程序会把他们认为是一个空间,所以这就和没加命名空间一样。可以改里面的名字,也可以改命名空间的名,也可以嵌套一个空间。

在这里插入图片描述

那么用的时候就是yy::xx::num。

3、命名空间的使用

前面的代码都已经放入了命名空间,现在再往yy里添加一些函数,比如push,init等,然后在外部调用。如果直接调用,肯定是不行的,程序会报错,这应该怎么解决?
现在对于这个问题,我们有三个办法解决。

指定命名空间访问

编译器自然不会让你一个个都加上

#include "yy.h"

int main()
{
	struct yy::Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
}

创建变量时带上命名空间即可,不过用不同的变量还是要每个都用符号,稍显麻烦,但也实用。

using全局展开

默认情况下,程序不会直接命名空间查找。但是我们可以把命名空间给展开,就像引用头文件一样。

#include "yy.h"
using namespace yy;

int main()
{
	struct Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
}

不加上using这一行代码,程序就不会去命名空间里找。加上就会找一遍yy.h里非命名空间的代码,再找一遍命名空间。

C++为了区分用户写的和标准库自带的,把标准库也放到了一个命名空间,就是std。
比如cout就是std里的。实际写代码时,我们可以全局展开,也可以带上std::。不过一般写项目时很少全部展开,因为全部展开后相当于没有命名空间了,所有标准库的代码都包含了进来,那么用户写代码时就会局限很多。所以指定访问也就有用处了。

部分展开

这里还有第三个办法。部分展开的意思是用什么展开什么。我要用cout,endl,那就展开这两个

#include <iostream>
using std::cout;
using std::endl;

四、C++输入输出

之前已经写过,<<是流插入,endl等价于换行符

#include <iostream>
using namespace std;

int main()
{
	cout << "hello world" << endl;
	cout << "hello world" << '\n';
	return 0;
}

现在我们可以这样理解,cout相当于一个控制台,hello world字符串流向cout,endl流向字符串。另外还有流提取,比如cin。从后面的变量中提取出来给到cin,cin >> n。

C++的流插入流提取有个很好的特性——自动识别类型

	//自动识别类型
	int n = 0;
	cin >> n;
	double* a = (double*)malloc(sizeof(double) * n);
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
	}
	for (int i = 0; i < n; i++)
	{
		cout << a[i] << endl;
	}
	return 0;

能够看到a和n类型不一样,但cin和cout都可以帮你解决问题。默认情况下保留5位小数,如果想要控制精度可以使用C语言的方法,比如"%.4f"等等,而C++方面的则要复杂。

五、缺省参数

C语言并没有缺省参数,实际上这个东西很有用。先看代码。

void Func(int a = 0)
{
	cout << a << endl;
}

int main()
{
	Func(1);
	Func();
	return 0;
}

实际输出结果是1和0.缺省参数就是如果不传参,就按照自带的数值运行,传参就用传的参数来运行。

多个参数且都是缺省参数时就是全缺省参数,可以全部传,也可以只传一个,但是不能隔开传,比如传了第1和第3个参数,必须连续传参。

void Func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << "  ";
	cout << "b = " << b << "  ";
	cout << "c = " << c << "  ";
	cout << endl;
}

int main()
{
	Func(1, 2, 3);
	Func(1, 2);
	Func(1);
	Func();
	return 0;
}

在这里插入图片描述

除此以外,还有半缺省参数。其实就是一部分缺省,但必须从右往左连续缺省。

void Func(int a, int b = 20, int c = 30)
{
	cout << "a = " << a << " ";
	cout << "b = " << b << " ";
	cout << "c = " << c << " ";
	cout << endl;
}

int main()
{
	Func(1, 2, 3);
	Func(1, 2);
	Func(1);
	return 0;
}

在这里插入图片描述

关于缺省参数的好处,我们可以联想一下之前的数据结构。比如栈,初始化malloc开空间时,我们总得先开一块,然后不断calloc,对于具体的数值可能操作者不知道是多少,所以代码比较麻烦。用上缺省参数的话,我们就可以往函数传数值,不传也没关系,有固定的数值。

struct Stack
{
	int* a;
	int top;
	int capacity;
};

void StackInit(struct Stack* ps, int n = 100)
{
	ps->a = (int*)malloc(sizeof(int) * n);
	ps->top = 0;
	ps->capacity = 0;
}

int main()
{
	Stack st;
	StackInit(&st);
	return 0;
}

缺省参数在使用的时候,头文件和源文件不能同时有缺省参数,否则程序会不清楚该用哪一个而报错。缺省参数在头文件声明时加上即可,加在源文件也会导致函数参数出错。

六、函数重载

前面说到的命名空间,可以解决同名变量。C语言中,同名函数也有同样的问题,只能改名,而C++有函数重载。

int Add(int left, int right)
{
	cout << left + right << endl;
	return 0;
}

double Add(double left, double right)
{
	cout << left + right << endl;
	return 0;
}

int main()
{
	Add(1, 2);
	Add(1.1, 2.2);
	return 0;
}

这段代码放在C语言里一定出错,但是C++却没有问题。对于这两个函数C++都能够识别出来并给出准确结果。函数重载一般的情况是两个函数参数类型,个数,类型顺序不同。顺序不同指的是像下图这样:

在这里插入图片描述

类型和个数相同,但是顺序不同也要重载。函数重载发生也要函数都在一个空间里,不是一个命名空间也就不会又重载。

函数重载貌似就这样简单地写完了,但是实际上有个关键性问题没有解决。为什么两个同名函数,C++真的能识别出来,C语言就不行?

编译器要先辨别出两个不同的函数,这样比起C语言是不是要慢一点?函数重载并不在运行时识别的,而是在编译阶段识别的。编译的时候C++对函数进行了处理,这个处理就是修饰了函数名。我们先打一个断点,转到反汇编去看。

在这里插入图片描述

在这里插入图片描述

可以看到两个函数下面都有一个call,后面括号里的地址也不一样。看一下调用两个函数那两行时程序在干嘛

在这里插入图片描述

在这里插入图片描述

所以可以看到两个函数在编译阶段就已经不一样了, 变成了一行行指令。虽然如此,还是有疑问。程序走到了调用函数的那一行后,程序是怎么知道就要去调用这个函数?

这里就牵扯到C++的修饰。C语言是按照函数名来查找,而C++是修饰过后按照修饰的指令来找。每个平台的修饰都不同,但规则都一样。所以每个函数也就变成了一些唯一的指令,C++通过这些指令找到每个函数。在C语言中如果用同名函数,就会出现这样:

在这里插入图片描述

在C++里,你可以看到这样

在这里插入图片描述

这时候报的外部符号就是修饰过的函数名了。
关于函数重载这里也并不是细致的说明,用linux的也可以去linux看看它如何修饰的。

七、引用

1、引用符号

用C语言的时候,指针要分为一级,二级,三级指针等等,为了改变实参的数据,我们总得想到传地址,用相应的指针接收,这个指针就麻烦,有可能就出错,所以C++就出了引用这个概念。C++的引用和Python的赋值相似。创建 i 这个变量并赋值后,我们可以把i当做这个值的标签,而引用则是又给它加了一个标签,所以我们可以给他加更多标签,也可以嵌套标签。引用后,新变量名的变化,旧变量名也会相应地变化了。

#include <iostream>
using namespace std;

int main()
{
	int a = 0;
	int b = a;
	int& c = a;

	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	return 0}

在这里插入图片描述

不过如上图那样,再来一个int& z = k, 那么z++后k和i的值都加一了。另外, 赋值的本质是什么?程序又创建了y这个变量,然后把值复制过去。所以j和k两个都++,不会影响到i。

2、引用的部分使用场景

void Swap(int* x, int* y)
{
	;
}

int main()
{
	int a = 0;
	int b = 1;
	Swap(&a, &b);
	return 0;
}

之前C语言想要改变实参的数值,就需要传地址。现在到了C++,我们用引用来实现。

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 0;
	int b = 1;
	Swap(a, b);
	cout << a << endl;
	cout << b << endl;
	return 0;
}

给a和b各自带上一个标签,也就是引用,那么x和y的改变就会影响到a和b了。
指针也一样可以引用,相当于两个指针指向同一块空间,不过名字不一样而已。

再看一下之前写链表的一个场景。

typedef struct Node
{
	struct Node* next;
	int val;
}Node;

void PushBack(Node* phead, int x)
{
	Node* newnode = (Node*)malloc(sizeof(Node) * 10);
	if (phead == NULL)
	{
		phead = newnode;
	}
}

int main()
{
	Node* plist = NULL;
	PushBack(plist, 1);
	PushBack(plist, 2);
	PushBack(plist, 3);
}

像这样的情况,我们就需要传二级指针才能改变链表的数据。但是在C++里,引用即可。

void PushBack(Node*& phead, int x)
{
	Node* newnode = (Node*)malloc(sizeof(Node) * 10);
	if (phead == NULL)
	{
		phead = newnode;
	}
}

下一篇再继续写。

结束。

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

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

相关文章

filebeat采集nginx日志

背景我们公司项目组用的是elastic的一整套技术栈&#xff0c;es&#xff0c;kibana&#xff0c;filebeat和apm&#xff0c;目前已经可以采集网关各个微服务的日志。架构图现在需要在原来的基础上把nginx这的日志也采集上来&#xff0c;方便做链路跟踪问题与思路原先traceId是在…

数字经济时代,“8K+”开拓行业新格局

2023深圳国际8K超高清视频产业发展大会召开&#xff0c;大会以“超清互联 数智创新”为主题&#xff0c;汇聚两院院士、产业领袖、领军企业共同深入探讨超高清产业发展现状、关键问题和未来趋势&#xff0c;并集中发布《深圳市超高清视频显示产业白皮书&#xff08;2023版&…

「数据密集型系统搭建」开卷篇|什么是数据密集型系统

在我们开发的诸多系统&#xff0c;基本都可以视为“数据密集型系统”&#xff0c;数据是一切物质的载体&#xff0c;我们依靠数据做存储记录&#xff0c;通过数据进行信息传递交换&#xff0c;最终还要数据来呈现和展示等&#xff0c;从一定视角而言&#xff0c;系统中最核心、…

临时用网搞不定?别着急,5G网络“急救车”来啦

如何在1天时间内&#xff0c;用不超过5名装维人员&#xff0c;完成超过200间宿舍的网络覆盖&#xff0c;让即将踏上考场的高三学子们尽快用上网络&#xff1f; 近期&#xff0c;这个问题一直困扰着重庆电信客户经理周睿。原来&#xff0c;由于疫情原因&#xff0c;重庆市某中学…

WINDOWS安装Oracle11.2.0.4

(一)Oracle服务器端安装 1.运行Oracle11g服务器端安装程序setup.exe,弹出如下界面&#xff1a; 2.如上界面中&#xff0c;把默认打上的勾去掉&#xff0c;然后点击【下一步】&#xff0c;弹出如下界面&#xff1a; 3.如上界面中&#xff0c;选择跳过软件更新,然后点击【下一步…

指针进阶(三)再谈数组与串函数

&#x1f31e;欢迎来到C语言的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f320;本阶段属于练气阶段&#xff0c;希望各位仙友顺利完成…

【阶段二】Python数据分析数据可视化工具使用01篇:数据可视化工具介绍、数据可视化工具安装、折线图与柱形图

本篇的思维导图: 数据可视化工具介绍 Matplotlib是最著名的绘图库,主要用于二维绘图,当然也可以进行简单的三维绘图。它提供了一整套丰富的命令,让我们可以非常快捷地用Python可视化数据,而且允许输出达到出版质量的多种图像格式。 Seaborn是在matplo…

国内电容市场份额达七成,松下如何抢占高地?

01 电容市场发展 电容器是三大电子被动元器件之一&#xff0c;是电子线路中不可缺少的基础元件&#xff0c;约占全部电子元件用量的40%&#xff0c;产值的66%。中国电容器行业规模增速持续高于全球规模增速&#xff0c;中国市场的快速增长成为拉动全球电容器行业规模增长的主要…

【Python从入门到进阶】2、Python环境的安装

接上篇《1、初识Python》 上一篇我们对Python这门编程语言进行了一个基本的了解&#xff0c;本篇我们来学习如何下载安装Python编程环境&#xff0c;以及如何使用pip管理Python包。 本篇讲解的是Windows环境下安装Python编程环境的步骤。 一、Python安装包下载 想要使用Pyth…

vue框架、element-ui组件库、font awesome图表库

一、vue 创建一个新vue项目。 vue create ProjectName 然后cd到该目录下&#xff0c;npm run serve启动服务器&#xff0c;即可打开。 二、组件库 element-ui是饿了么的&#xff0c;ArcoDesign是字节的&#xff0c;有很多。 install见官方文档&#xff1a;组件 | Element 导入…

黑马学SpringAMQP

目录&#xff1a; &#xff08;1&#xff09;SpringAMQP的基本介绍 &#xff08;2&#xff09;SpringAMQP-入门案例的消息发送 &#xff08;3&#xff09; SpringAMQP-入门案例的消息接收 &#xff08;4&#xff09;SpringAMQP-WorkQueue模型 &#xff08;5&#xff09;Sp…

408数据结构考点总结

第一章 绪论 考点 1&#xff1a;时间复杂度与空间复杂度 时间复杂度 定义&#xff1a;将算法中基本运算的执行次数的数量级作为时间复杂度&#xff0c;记为O(n)O(n)O(n)。 计算原则 加法法则&#xff1a;T(n)T1(n)T2(n)O(f(n))O(g(n))O(max⁡(f(n),g(n)))T(n)T_{1}(n)T_{2…

安全—02day

XMLHttpRequest 对象 AJAX 通过原生的XMLHttpRequest对象发出 HTTP 请求&#xff0c;得到服务器返回的数据后&#xff0c;再进行处理。现在&#xff0c;服务器返回的都是 JSON 格式的数据&#xff0c; XMLHttpRequest本身是一个构造函数&#xff0c;可以使用new命令生成实例。…

T113_PRO-S3_GPS解析

今天主要是以市面上能买到的最新款的GPS作为解析的依据&#xff0c;市面上能买的GPS目前最新的串口打印的格式主要是如下&#xff1a; $GNGGA,085126.000,2311.77819,N,11323.44968,E,1,15,1.5,36.7,M,0.0,M,,*4C $GNGLL,2311.77819,N,11323.44968,E,085126.000,A,A*4B $GPGSA…

Java入门-0基础学Java-01Java环境变量配置

JDK的下载与安装jdk下载地址&#xff1a;https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html选择与电脑系统匹配的版本进行下载&#xff08;Windows系统如果是32位下载Windows x86&#xff0c;64位下载Windows x64&#xff0c;苹果的下载M…

Go语言设计与实现 -- 调度器总体概述

Go语言调度器使用与CPU数量相等的线程来减少线程频繁切换带来的内存开销&#xff0c;同时在每一个线程上执行额外开销更低的Goroutine来降低操作系统和硬件的负载。 每一次线程上下文切换都需要消耗约1us的时间&#xff0c;而Go调度器对Goroutine的上下文的切换约为0.2us&#…

01_FreeRTOS基础知识

目录 裸机与RTOS介绍 裸机与RTOS特点 FreeRtos简介 任务调度简介 抢占式调度 时间片调度 协程式调度 任务状态 裸机与RTOS介绍 假设小明在打游戏,此时女盆友微信回复了信息。 裸机:在裸机上实现是等这游戏打完之后,在去回复女朋友的信息,假设游戏刚刚开始打完需要半小…

使用缓存保护MySQL

1 更新缓存最佳实践 Redis的执行器非常薄&#xff0c;所以Redis只支持有限API&#xff0c;几乎没聚合查询能力&#xff0c;也不支持SQL。存储引擎也简单&#xff0c;直接在内存中用最简单数据结构保存数据。 如Redis的LIST在存储引擎的内存中的数据结构就是双向链表。内存是易…

基于ONNX人脸识别实例(SCRFD/ArcFace)-C#版

一、引用 Microsoft.ML.OnnxRuntime OpenCvSharp OpenCvSharp.Extensions二、人脸检测(Face Detection) using System; using System.Collections.Generic; using System.Linq; using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp;…

c++11 标准模板(STL)(std::deque)(十)

定义于头文件 <deque> std::deque 修改器 移除首元素 std::deque<T,Allocator>::pop_front void pop_front(); 移除容器首元素。若容器中无元素&#xff0c;则行为未定义。 指向被擦除元素的迭代器和引用被非法化。若元素是容器中的最后元素&#xff0c;则尾后…