【C++】C++ 入门(一)

news2024/12/24 9:11:43

目录

一、前言

1、什么是C++

2、C++关键字(C++98)

二、第一个C++程序

三、命名空间

1、存在意义

2、命名空间定义

3、命名空间的使用

3.1、指定命名空间访问

3.2、全局展开访问

3.3、部分展开访问

四、C++输入&输出

五、缺省参数

1、缺省参数概念

2、缺省参数分类

2.1、全缺省参数

2.2、半缺省参数

3、缺省参数的实际使用

4、总结

六、函数重载

1、函数重载的概念

2、C++支持函数重载的原理


一、前言

1、什么是C++

 C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了 OOP(object oriented programming:面向对象)思想 ,支持面向对象的程序设计语言应运而生。

 1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了 面向对象 的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计

2、C++关键字(C++98)

 C++总计63个关键字,C语言32个关键字。
ps:下面我们只是看一下C++有多少关键字,不对关键字进行具体的讲解。后面我们学到以后再
细讲:

asmdoifreturntrycontinue
autodoubleinlineshorttypedeffor
booldynamic_castintsignedtypeidpublic
breakelselongsizeoftypenamethrow
caseenummutablestaticunionwchar_t
catchexplicitnamespacestatic_castunsigneddefault
charexportnewstructusingfriend
classexternoperatorswitchvirtualregister
constfalseprivatetemplatevoidtrue
const_castfloatprotectedthisvolatilewhile
deletegotoreinterpret_cast

二、第一个C++程序

 不管是学习什么语言,我们学习道路的起点总是打印一个 "hello world" 。所以我们就先从使用 C++ 打印 "hello world" 来开始本章内容的学习吧。

 因为 C++ 是兼容 C语言 的,所以我们打印内容时依然可以使用库函数 printf 。不过一般我们在写 C++ 时,更喜欢使用 cout << "hello world" << endl :

#include <iostream>
using namespace std;

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

	return 0;
}

 运行代码,hello world 就被打印出来了。

这段程序包含了两点知识:

 一个是 io流 相关的,比如 "<<" 符号是什么意思。另一个是 命名空间 相关的,比如 namespace 是什么意思。

下面我们就以此为展开,开始本章内容的学习。

三、命名空间

1、存在意义

 最开始时,C++出现是为了解决C语言的一些不足。就比如,在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突, namespace 关键字的出现就是针对这种问题的。

举例说明一下:

 我们这样写代码,程序正常执行,但是如果我们增加一个头文件 stdlib.h ,再来看一下结果: 

 可以发现程序直接报错,提示 rand 被重定义了。这是因为我们自己定义的名称与头文件 stdlib .h 里面的名称重复冲突了。

 这就会引起一些我们不愿意看到的结果,试想一下,以后我们在项目组里与同事共同协作完成一个项目时,每个人分工写不同模块的代码,是完全有可能使用相同名称的变量、函数名等等的。那这种情况下怎么办呢?让他们全部返工修改吗,这样显然是很不合理的。所以我们需要使用 namespace 来定义命名空间。

2、命名空间定义

在项目开发中,员工A写了一个队列,员工B写了一个链表,他们使用了相同的结构体名称Node:

他们在各自的程序里都没有什么问题,但是当把互相的代码结合到一起时,就会发生命名冲突的报错:

 解决方法很简单:我们在程序中增加一个命名空间 namespace ,命名空间定义的是一个域,名为命名空间域。让员工A和员工B把程序放到各自的命名空间域里面去,就不会再发生冲突了。

 有别于局部域和全局域,局部域和全局域影响变量的使用范围和生命周期,而命名空间域只影响变量的使用范围,不影响生命周期

 这时我们再运行合并程序,程序就不会再报错了

 解决了一个问题之后,我们又遇到了一个新的问题,那就是我们在使用这两个头文件中的结构体类型时,编译不通过。

 显示这个结构体变量未定义,可是我们已经在上面两个头文件里都定义过结构体 Node 了,为什么还提示未定义呢?

 上面我们说过,命名空间域不会影响生命周期,但是会影响使用范围。我们在调用各种类型、变量等等东西的时候,默认先在局部域寻找,再去全局域寻找,如果都没找到,程序就会报错。也就是说程序不会主动到命名空间域里寻找。

因此,我们定义了命名空间后,需要程序员主动去使用,而不是靠系统程序自动寻找。

3、命名空间的使用

我们使用命名空间有三种方式

3.1、指定命名空间访问

 我们使用 "::" 符号来访问命名空间,该符号称为作用域限定符,命名空间写在作用域限定符之前,类型、变量名称写在作用域限定符之后。

这样一来编译就成功了。

 需要注意的是, "::" 是写在 Node 前面的,而没有写在 struct Node 前面,这时因为 struct 是结构体类型的前缀,真正同名冲突的是 Node 。

如果 "::" 前不加命名空间,则表明命名空间为全局域。

3.2、全局展开访问

  为了防止命名冲突,我们会把变量、类型包到命名空间里面去。使用的时候再借助作用域限定符取出,但是这样使用会有一个问题。

 那就是当我们需要频繁使用命名空间里的类型时,就需要不断的写入命名空间与作用域限定符,太过于繁琐,因此我们有了第二种方法:使用 using 将命名空间中某个成员引入

 相当于把命名空间 RDA 在程序里展开了,大家可以理解为程序在寻找类型时,不仅会在局部域和全局域里寻找,还会在命名空间 RDA 里寻找。

 所以在一般情况下,我们不建议使用全局展开,因为使用了全局展开之后,我们定义命名空间的意义就没有了。我们平时进行C++代码练习时,为了方便,可以使用全局展开

3.3、部分展开访问

 那么为了能够解决 指定命名空间访问 的繁琐的问题,又要尽量避免使用 全局展开访问。我们来学习第三种方法:使用 using namespace 命名空间名称引入

我们先修改一下代码:

 我们想要多次、频繁的使用 cout endl ,又不想每一次使用都这么麻烦,但是如果直接把命名空间 std 全局展开又太过了。

这时我们就可以把常用的变量、类型、函数等部分展开:

 这样就可以在程序中直接使用了。

四、C++输入&输出

接下来我们来讲解C++中,输入与输出的操作:

 我们使用 cout << "hello world" << endl;实现了在屏幕上打印 "hello world" 的功能。

其中运算符 "<<" 流插入运算符,也叫流向。enl 为换行,等价于 "\n" 。

 cout 是一个 ostream 类型的对象,这个大家暂时不必理解,后面的文章会详细讲解,暂时把他看作控制台就可以了。

 同样还有一个运算符 ">>" 流提取运算符,可以搭配 cin 使用。 cin 是一个 istream 类型的对象,大家同样暂时可以当作控制台看待。

  cout cin 分别为 输出 与 输入,他们与C语言有一个不同的地方,那就是可以自动识别类型。举个例子:

#include <iostream>
using namespace std;

int main()
{
	int n = 0;
	cin >> n;  //输入数字赋值给 n
	double* a = (double*)malloc(sizeof(double) * n);	
	if (a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	//输入数字赋值给数组 a
	for (int i = 0; i < n; ++i)
	{
		cin >> a[i];
	}
	for (int i = 0; i < n; ++i)
	{
		cout << a[i] << endl;
	}

	return 0;
}

 我们先使用 cin int 型变量 n 赋值,再给 double 型数组 a 赋值,并使用 cout 把数组打印出来:

 可以看到我们在输入输出的时候并没有指定类型,都是 cin cout 自动识别的,利用这个特性,我们以后的操作会非常的方便。

 如果我们想控制输出精度,使用 cout 来控制过于复杂,建议直接使用 printf 函数来操作。

总结:

  1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
  2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含<iostream >头文件中。
  3. <<是流插入运算符,>>是流提取运算符。
  4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
  5. 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,这些知识我们后面再来学习,所以我们这里只是简单学习他们的使用。后面我们会更深入的学习IO流用法及原理。
     

五、缺省参数

1、缺省参数概念

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

例如:

#include <iostream>
using namespace std;
void Func(int a = 0)
{
	cout << a << endl;
}

int main()
{
	Func(1);
	Func();

	return 0;
}

当我们主动指定参数给函数时,函数就使用我们指定的参数,否则就使用缺省值。

 缺省参数不能 函数声明 定义 中同时出现,这时为了避免出现函数声明和定义中缺省参数给的不同而出现的错误。

 如果我们同时写了 函数声明 和 定义,在给缺省参数时,要在函数声明中给。


2、缺省参数分类

2.1、全缺省参数

在声明或定义函数时,我们可以设置多个缺省参数,并且按照从右向左的顺序优先缺省:

#include <iostream>
using namespace std;
void Func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << endl;
}

int main()
{
	Func(1, 2, 3);
	Func(1, 2);
	Func(1);
	Func();

	return 0;
}

 使用缺省值时,必须要从右往左连续使用

2.2、半缺省参数

必须从右往左连续缺省,不能间隔着给。

 如果函数使用半缺省参数,那么该函数在调用时,一定要指定参数。有几个参数不缺省,就至少要指定几个参数。 

3、缺省参数的实际使用

 在了解了缺省参数的概念以及使用方法之后,我们来看一下缺省参数实际使用时的场景。

 在之前我们学习栈的时候,我们知道栈是通过数组实现的。在栈的初始化时,需要给数组设定一个初始容量大小,这个大小我们之前是设置的 4 。

#include <stdio.h>
#include <corecrt_malloc.h>
struct Stack
{
	int* a;
	int top;
	int capacity;
};
void StackInit(struct Stack* ps)
{
	ps->a = (int*)malloc(sizeof(int) * 4);
	ps->top = 0;
	ps->capacity = 4;
}
int main()
{
	struct Stack st1;//要存 100 个数
	StackInit(&st1);
	struct Stack st2;//不知道要存多少个数
	StackInit(&st2);

	return 0;
}

 这种写法其实是不好的。假设有这样一个场景:我们需要两个栈,一个栈要存放 100 个数据,另一个栈不知道要存放多少个数据。如果这两个栈我们都初始化成了 4 ,就很不合理,因为我们都已经知道自己要存 100 个数据了,再让这个栈一次又一次的扩容,会存在资源的浪费。但是如果我们直接就把栈的容量初始化成 100 ,那另一个不知道要存放多少数据的栈又可能用不了这么多,存在空间的浪费。

 所以最好的方法就是使用缺省参数:

#include <stdio.h>
#include <corecrt_malloc.h>
struct Stack
{
	int* a;
	int top;
	int capacity;
};
void StackInit(struct Stack* ps, int defaultCapacity = 4)
{
	ps->a = (int*)malloc(sizeof(int) * defaultCapacity);
	ps->top = 0;
	ps->capacity = 4;
}
int main()
{
	struct Stack st1;
	StackInit(&st1, 100); //直接指定参数 100
	struct Stack st2;
	StackInit(&st2); //不指定参数

	return 0;
}

4、总结

  1. 半缺省参数必须从右往左依次来给出,不能间隔着给。
  2. 缺省参数不能 函数声明定义 中同时出现。
  3. 缺省值必须是 常量 或者 全局变量
  4. 仅支持C++,不支持C语言(编译器不支持)。
     

六、函数重载

 在C语言中,是不允许多个函数名相同的。这样会导致我们在使用几个功能相类似的函数时,要取不同的名字,并且在使用时也要分开使用。

1、函数重载的概念

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

例如:

#include <iostream>
using namespace std;

int Add(int num1, int num2)
{
	cout << "int Add(int num1, num2)" << endl;

	return num1 + num2;
}

double Add(double num1, double num2)
{
	cout << "Add(double num1, double num2)" << endl;

	return num1 + num2;
}
int main()
{
	Add(1, 2);
	Add(1.1, 2.2);

	return 0;
}

可以看到,C++支持使用形参列表不同的同名函数,并且可以根据参数类型的不同自动识别调用的是哪一个函数。

2、C++支持函数重载的原理

 既然C++支持函数重载,那在性能上会不会因为要判断到底是使用哪一个函数而有所下降呢?其实是不会的,因为函数的类型不是在程序运行的时候才开始匹配的,而是在编译链接时就已经匹配完成了

 这里就体现出了C++与C语言的区别,C++在编译时,对函数名进行了修饰。由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,我们就以 g++ 对函数名修饰为例:

 在 Linux 中,g++对函数 int Add(int num1, int num2) 作了修饰之后,函数名变为了 _Z3Addii _Z是固定前缀,3 是原本函数名(Add)中字符的个数,最后的 ii 是函数中参数类型(int,int)的首字母。同理,函数 double Add(double num1, double num2) 做了修饰之后,函数名变为 _Z3Adddd

g++的函数修饰后,函数名变成【_Z+函数长度+函数名+类型首字母】


我们来实际操作一下,加深印象:

先使用C语言来操作,我们编写如下代码:

 使用 gcc 编译之后,输入 objdump -S 指令转到反汇编:

 可以看到编译后的函数名就是我们在源程序中写入的 fun ,没有发生变化。


现在我们使用C++来操作:

还是同样的代码,这次我们使用 g++ 来编译,转到反汇编:

 可以看到函数名已经被修饰,且修饰规则为【_Z+函数长度+函数名+类型首字母】

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

如果C++中两个函数函数名和参数是一样的,返回值不同不构成重载的,因为调用时编译器没办法区分。


下面我们再来看一下 Windows 系统下vs的命名规则,因为比较复杂,我们仅作了解:

对比Linux会发现,windows下vs编译器对函数名字修饰规则相对复杂难懂,但道理都是类似的,我们就不做细致的研究了。


以上就是C++入门第一部分的内容,主要介绍了命名空间、C++输入与输出、缺省参数以及函数重载等方面的知识,希望同学们多多支持,如果有错误的地方希望大佬指正,谢谢!

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

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

相关文章

【Day4】24两两交换链表中的节点、19删除链表的倒数第N个节点、链表相交、142环形链表Ⅱ

【Day4】24两两交换链表中的节点、19删除链表的倒数第N个节点、160链表相交、142环形链表Ⅱ24.两两交换链表的点19.删除链表的倒数第N个节点160链表相交 面试题02.07142 环形链表Ⅱ判断链表是否有环若链表有环&#xff0c;如何找到环的入口24.两两交换链表的点 题目链接&#…

Spacedesk 安装教程及连接后黑屏解放方法

spacedesk 安装教程1. Spacedesk 概述2. Spacedesk 安装教程2.1 下载 Spacedesk2.2 连接计算机的 Spacedesk3. 被拓展的设备连接后黑屏的解决方法结束语1. Spacedesk 概述 Spacedesk 是一款低延迟的免费显示器拓展软件&#xff0c;且不需要线材将不同设备连接&#xff1b; Spa…

MySQL中的普通索引和唯一索引实际开发中的选择

文章目录前言一、普通索引和唯一索引介绍二、查询语句的比较三、更新语句的比较四、索引的选择和实践前言 本文我们将会从针对普通索引与唯一索引的增删改查的具体执行流程&#xff0c;来看看效率的对比。以便让我们在实际业务开发中可以进行更好的选择。 一、普通索引和唯一索…

动态规划系列 —— 背包问题

什么是背包问题 背包问题是有N件物品&#xff0c;容量为V的背包 每个物品有两个属性&#xff1a;体积&#xff0c;价值&#xff0c;分别用数组v&#xff0c;w表示 第i件物品的体积为v[i]&#xff0c;价值为w[i] 计算在背包装得下的情况下&#xff0c;能装的最大价值是多少&…

MATLAB 图像处理大作业

1、基础知识利用 MATLAB 提供的 Image file/IO 函数完成以下处理&#xff1a;&#xff08;a&#xff09;以测试图像中心为圆心&#xff0c;图像长宽中较小值一半为半径画一个红颜色的圆&#xff1b;&#xff08;b&#xff09;将测试图像涂成国际象棋状的‘黑白格’样子&#xf…

华芯片特微 M33内核 KEIL5环境配置不上问题

1 JFLASH连接不上问题 官方手册有说解决这个问题 2 JFLASH能连接上KEIL提示no found sw-dp 在替换keil下载算法后还是提示no found sw-dp 1 怀疑是keil 527版本太高了, 就换了518 还是不行 2 怀疑是keil检测到盗版了就不让下, 替换Jlink为以前老版本还是不行 解决方案: 下…

聊天气泡图片的动态拉伸、适配与镜像

聊天气泡图片的动态拉伸、适配与镜像前情提要创建.9.png格式的图片从资源文件夹加载.9.png图片从本地文件加载“.9.png”图片项目痛点进阶探索iOS中的方式Android中的探索构造chunk数据构造padding数据镜像翻转功能屏幕的适配简单封装演示示例一条线段控制的拉伸两条线段控制的…

Pandas 安装与教程

前言Pandas 是 Python 语言的一个扩展程序库&#xff0c;用于数据分析。Pandas 是一个开放源码、BSD 许可的库&#xff0c;提供高性能、易于使用的数据结构和数据分析工具。Pandas 名字衍生自术语 "panel data"&#xff08;面板数据&#xff09;和 "Python data…

[apidoc]Apidoc-文档生成工具

Apidoc主要是用于生成API文档的工具&#xff0c;可以用于多种语言&#xff0c;包括java、javascript、php等 这里主要是为了写前端的APIDOC&#xff0c;方便交互是双方的使用; 工具的安装 工具包的安装 npm i apidoc [-g|-D]可以-g全局安装&#xff0c;或者-D局部安装,因为…

网盘系统|基于SpringBoot的网盘系统的设计与实现

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

【无功优化】考虑泄流效应的光伏并网点电压系统侧无功优化(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

软考中级,【软件评测师】经验分享

&#xff0c;以下是我的考试成绩&#xff0c;一次通过很是幸运&#xff0c;希望把我的好运传递给大家&#xff0c;大家都能一次通过谈经验之前&#xff0c;先和大家说说考试的题型以及考试的内容&#xff0c;根据往年的考试题目我们可以很容易得知&#xff0c;软件评测师考试分…

Cisco(62)——PBR策略路由案例

场景1-单下一跳: 拓扑: 需求: R1和R2均连接100.100.100.100,R4看做一台PC,当PC访问100.100.100.100的时候优先走左边,当左边down掉之后切换到右边链路,使用PBR操作。 实现: 1.IP地址等基本配置 R4: R4(config)#no ip routingR4(config)#int e0/0 R4(config-if)#ip add…

Typora自动上传文章图片太难折腾?十三行JavaScript代码足矣

前言 Typora是我用过最爽的markdown文本编辑器了。但是有一点很让人难受&#xff0c;就是在写文章的时候&#xff0c;粘贴上的图片是本地路径。这就导致在复制文章到各大博客平台时发表&#xff0c;图片无法显示。然后需要各种办法去处理文章中的图片&#xff0c;不仅要手动上传…

【学习笔记】【Pytorch】十、线性层

【学习笔记】【Pytorch】九、线性层学习地址主要内容一、前言二、Pytorch的线性层三、Linear类的使用1.使用说明2.代码实现学习地址 PyTorch深度学习快速入门教程【小土堆】. 主要内容 一、前言 在神经网络中&#xff0c;我们通常用线性层来完成两层神经元间的线性变换。 …

【C++】面向对象---继承(万字详解)

目录前言一、继承的定义及概念二、继承方式三、基类和派生类之间的转换四、切片五、继承中的作用域六、派生类中的默认成员函数七、继承中的友元与静态成员继承与友元继承中的静态成员八、棱形继承和虚继承棱形继承虚继承总结前言 继承是面向对象的一个重点&#xff0c;而继承…

活动星投票医疗保障案例推介网络评选微信的投票方式线上免费投票

“医疗保障案例推介”网络评选投票_线上免费投票系统_功能齐全的微信投票_在线免费投票用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票…

图形编辑器:标尺功能的实现

大家好&#xff0c;我是前端西瓜哥。今天我们来实现图形编辑器的标尺功能。 项目地址&#xff1a; https://github.com/F-star/suika 线上体验&#xff1a; https://blog.fstars.wang/app/suika/ 标尺指的是画布上边和左边的两个有刻度的尺子&#xff0c;作用让用户知道他正在编…

java 探花交友day2 项目简介,环境搭建 登录验证码

技术方案&#xff1a; 项目结构&#xff1a; 项目概述 通过接口文档&#xff08;API文档&#xff09;定义规范 开发工具安装与配置 Linux虚拟机 YAPI 账号 tanhuaitcast.cn 密码123456 安装个安卓模拟器&#xff0c;然后安装APK 开发环境说明 初始工程搭建 阿里云短…

Leetcode:235. 二叉搜索树的最近公共祖先(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 递归&#xff1a; 原理思路&#xff1a; 精简版&#xff1a; 迭代&#xff1a; 原理思路&#xff1a; 问题描述&#xff1a; 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先…