【C++学习】基础语法(一)

news2024/11/20 4:29:26

1、背景知识

1.1 什么是C++

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

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

1.2 C++的发展历史

  1979年,贝尔实验室的本贾尼等人试图分析Unix内核的时候,试图将内核模块化,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称之为C with classes。
C++创始人:本贾尼
             C++创始人:本贾尼

  下图为C++在不同时间的历史版本:

1.3 C++的使用广泛度

  下图数据来源于TIOBE编程语言社区2023年1月4日的最新排行榜,在30多年的发展中,C/C++排名一直稳居前五。

image-20230104201350733

  由此可以看出,C/C++、Java是目前比较主流的程序语言,尤其是C++语言掌握者适合在操作系统及大型软件开发、服务器端开发、游戏开发、嵌入式和物联网、数字图像处理、人工智能、分布式应用等领域工作。

2、基础语法

2.1 "::"域作用限定符

  域作用限定符表示作用域,和所属关系。下列代码中,coutendl属于std, 而std是C++标准库中函数或者对象

int main()
{
	std::cout << "Hello World" << std::endl;
	std::cout << "Hello World" << "\n";
	return 0;
}

  endl表示换行,类似于C语言中的’\n’,cout表示类似于C语言中printf的格式化输出;

调试结果:

image-20230104205905249

2.2 命名空间

  在C/C++中,大量存在着变量、函数、类,这些都存在于全局作用域中,会导致名字冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或者名字污染namespace关键字的出现就是针对这种问题。

下图中,在只包含标准输入输出库stdio中,全局变量rand能够正常使用:

image-20230104212155984

  但加入了标准库函数头文件后,全局变量rand就被“重定义”报错了,这是因为在stdlib中又随机函数rand,与下图的全局变量rand命名冲突了。

image-20230104212541176

例如,下列代码中,全局域和局部域中整型变量a的名字都相同,C语言中局部域无法调用全局域变量a

int a = 1;

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

void f2()
{
	int a = 1;
}

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

调试结果:

image-20230104214726172

C++在局部域的输出函数中添加域作用限定符,使得局部域中也能调用全局域的变量。

image-20230104214818029

上图中,::的前面空格表示在全局中查找,不能在其他函数中查找。

2.2.1 命名空间的定义

  在C++中,定义命名空间需要使用关键字namespace,后面跟着命名空间的名字,然后接一对花括号{},{}中为命名空间的成员。

  1. 一般命名空间的定义事例:
namespace joes
{
    int rand = 10;
    int Add(int left,int right)
    {
        return left + right;
    }
    struct Node
    {
        struct Node* next;
        int val;
    }
}
  1. 命名空间的嵌套事例:
namespace P1
{
    int a;
    int b;
    int Add(int left,int right)
    {
        return left + right;
    }
    namespace P2
    {
        int c;
        int cp;
        int Sub(int left,int right)
        {
            return left - right;
        }
    }
}
  1. 命名空间的合并:

AA.h头文件

namespace joes
{
    int Add(int* a,int* b)
    {
        int tmp = *a;
        *a = *b;
        *b = tmp;
    }
}

BB.h头文件

namespace joes
{
    int Add(int& x,int& y)
    {
        int tmp = x;
        x = y;
        y = tmp;
    }
}

同一个工程中允许存在多个相同名称的命名空间,如上例中的joes,编译器最后会合成同一个命名空间中joes

2.2.2 命名空间的使用

主函数:

int main()
{
	struct AList::Node node1;
	struct BQueue::Node node2;
	AList::min++;
	BQueue::min++;
	return 0;
}

List.h头文件:

namespace AList
{
	struct Node
	{
		struct Node* prev;
		struct Node* next;
		int val;
	};
	int min = 1;
}

Queue.h头文件:

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

	struct Queue
	{
		struct Node* head;
		struct Node* tail;
	};
	int min = 0;
}

2.3 C++的输入与输出

  当我们在学C语言时,编写的第一个程序为输出"Hello World":

#include<stdio.h>//C语言的标准输入输出库
int main()
{
    printf("Hello Word\n");
    return 0;
}

而Python亦较为简洁:

print("Hello World")

那么C++是如何实现的?

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

image-20230106213650709

注意:

  1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含头文件以及命名空间使用方法使用std;
  2. **<<是流插入运算符,>>**是流提取运算符;
  3. C++的输入输出不需要像printfscanf那样手动控制格式,C++的coutcin能够自动识别变量类型;
  4. 在日常学习中,建议直接using namespace std即可;但using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 +using std::cout展开常用的库对象/类型等方式。

2.4 缺省参数

2.4.1 缺省参数概念

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

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

int main()
{
	Func();//没有传参数时,使用参数的默认值0
	Func(1);//传参数时,使用指定的实参1
	return 0;
}

调试结果:

image-20230107194041408

2.4.2 缺省参数分类

  1. 全缺省参数
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;
}

调试结果:

image-20230107195044938

注意:使用缺省值必须从右往左连续使用。

  1. 半缺省参数
void Func(int a, 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);
	return 0;
}

调试结果:

image-20230107195713944

注意:半缺省必须从右往左连续缺省。

2.4.3 缺省参数的实际应用

  例如数据结构中,栈的建立,具体详见我的上篇博文【数据结构】超详细——动态栈

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

void StackInit(struct Stack* ps,int defaultCapacity = 4)
{
	ps->a = (int*)malloc(sizeof(int) * defaultCapacity);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	ps->top = 0;
	ps->capacity = defaultCapacity;
}

int main()
{
	Stack st1;//最多要存100个数据时
	StackInit(&st1, 100);

	Stack st2;//不知道有多少数据时
	StackInit(&st2);
	return 0;
}

此外,缺省参数不能在函数声明和定义中同时出现。

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

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

下面为头文件:

void Func(int a = 10);

调试结果:

image-20230107200909447

出现错误是由于程序的头文件中,函数Func声明和C++程序中Func的定义都使用了缺省参数。修改声明后:

void Func(int a);

调试结果:

image-20230107201251729

修改后程序正常执行,亦可以修改函数的定义文件,删去缺省参数。

image-20230107201627231

2.5 函数重载

  自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载。

2.5.1 函数重载概念

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

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

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

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

调试结果:

image-20230107203232291

类型顺序不同:

void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
	cout<<endl;
}

void f(char b, int a)
{
	cout << "f(char b,int a)" << endl;
	cout << "b=" << b << endl;
	cout << "a=" << a << endl;
	cout << endl;
}

int main()
{
	f(10, 'j');
	f('u', 20);
	return 0;
}

调试结果:

image-20230107203641810

上例中,函数名相同,形式参数列表的类型顺序不同以及类型不同。

2.5.2 C++支持函数重载的原理–名字修饰(name Mangling)

  C/C++语言中,一个程序要运行起来,需要经历以下几个阶段:预处理编译汇编链接

image-20230107221321674

预处理:文件展开,条件编译,宏替换,去注释等;

编译:C++语言汇编语言;

汇编:将编写的代码翻译成二进制目标文件;

链接:将形成的.obj文件和库文件合并,形成可执行程序。

根据上图,编写具如下程序:

image-20230107213908231

对程序进行预处理:

image-20230107214000809

对程序进行编译:

image-20230107214030257

对程序进行汇编:

image-20230107214105341

对程序进行连接:

image-20230107214129718

调试结果:

image-20230107214148622

采用C++语言编写的test.cpp程序,g++编译的结果可知,函数名的修饰发生变化,编译器将函数参数类型信息添加到修改后的名字中,g++的函数修饰后变成【_Z+函数长度+函数名+类型首字母】。

image-20230107214951667

而函数重载时,g++编译后函数修饰名具体为:

image-20230107223339729

而在linux环境中,采用gcc编译C语言程序后,函数名字的修饰没有发生改变:

image-20230107220953011

注意

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

2.6 引用

2.6.1 引用概念

引用不是新定义一个变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

例如:林允儿,人称“允儿”,江湖人称“小鹿”。

林允儿
                林允儿
类型& 引用变量名(对象名)= 引用实体

例如下列代码中,变量ki的别名,m亦是i的别名,而nk的别名:

int main()
{
	int i = 0;
	int& k = i;//引用

	int j = i;

	cout <<"i的地址:"<< & i << endl;
	cout <<"j的地址:"<< & j << endl;
	cout <<"k的地址:"<< & k << endl;

	++k;
	++j;

	int& m = i;
	int& n = k;
	++n;

	return 0;
}

变量ijk的地址为:

image-20230106211314747

由此可知,引用不在内存中开辟新的空间。此外,引用类型必须和引用实体是同种类型的。

2.6.2 引用特性

  1. 引用在定义时必须初始化;
  2. 一个变量可以有多个引用;
  3. 引用一旦引用一个实体,再不能引用其他实体。
int main()
{
	int i = 11;
	int* p = &i;
	int*& rp = p;
	return 0;
}

若引用定义时未初始化,则会出现下图的报错提醒:

image-20230106212836139

在上述代码行中,iprp引用。

2.6.3 常引用

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

void TestConst()
{
	const int a = 10;
	const int& ra = a;	
	const int& b = 10;
}

int main()
{
	TestConst();
	return 0;
}

调试结果:

image-20230107224358630

由此可见,代码执行正常。但常见下面错误:

void TestConst()
{
	const int a = 10;
	int& ra = a; 
}

int main()
{
	TestConst();
	return 0;
}

调试结果:

image-20230107224613018

这是由于变量a是常量,引用时遗落了常量类型关键字const

在这里插入图片描述

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

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

相关文章

Python | Matplotlib | 不完全总结

本文对 Matplotlib 的用法进行不完全总结。 更新&#xff1a; 2023 / 1 / 4 Python | Matplotlib | 不完全总结ImageMagick导库画布创建多子图动图2D柱状图基本&#xff1a;水平 / 垂直柱形主题&#xff1a;颜色、文字、网格线动图线图基本动图3D柱状图基本线图动图参考链接Im…

Web文件操作:上传与下载

文件上传与下载文件上传文件上传的实现表结构设计UploadFileServiceImpl的实现上传文件遇到的问题与解决文件下载文件上传 文件上传的表单中&#xff0c;需要注意的三个地方&#xff1a; 1.表单的请求方式必须为post&#xff1b; 2.表单域必须有file类型&#xff1b; 3.表单的e…

活动星投票奋斗青春,使命必达网络评选微信的投票方式线上免费投票

“奋斗青春&#xff0c;使命必达”网络评选投票_如何进行投票推广_参与投票活动_小程序的投票发展现在来说&#xff0c;公司、企业、学校更多的想借助短视频推广自己。通过微信投票小程序&#xff0c;网友们就可以通过手机拍视频上传视频参加活动&#xff0c;而短视频微信投票评…

英伟达528.02驱动发布支持4070 Ti!GFE新增9款游戏

自GTX 4070 Ti显卡发售后&#xff0c;英伟达便随即发布了支持该新显卡的Game Ready 528.02驱动&#xff0c;同时为《战意》和《达喀尔沙漠拉力赛》两款新游戏带来DLSS 3的支持&#xff0c;DLSS 3的队伍再度壮大&#xff01; 驱动人生现已支持英伟达Game Ready 528.02驱动&…

围绕http请求头中Referer展开的一些知识

1. 什么是referer&#xff1f; <点击以获取跳转信息 >跳转过去记得按一下f12点击网络请求详情&#xff0c;再刷新一下&#xff0c;就可以看见referer字段&#xff1a; 当我们尝试在浏览器内部直接输入这熟悉的网址时&#xff0c;此时刷新后则是这样一番景象&#xff1…

C++类和对象的基本概念

目录 1.c和c中struct的区别 2.类的封装 3.类的访问权限 1.c和c中struct的区别 c语言中结构体中不能存放函数,也就是数据(属性)和行为(方 法)是分离的 c中结构体中是可以存放函数的,也就是数据(属性)和行为 (方法)是封装在一起的 #define _CRT_SECURE_NO_WARNINGS #include …

基于Python tensorflow机器学习的人脸识别登陆系统源码、人脸注册系统源码

face_login 代码下载地址&#xff1a;基于Python tensorflow机器学习的人脸识别登陆系统源码、人脸注册系统源码 介绍 本项目基于tensorflow机器学习&#xff0c;实现web端人脸识别登陆&#xff0c;人脸注册。 提供手机端页面(face_login_app)和网页端页面(vue_element-adm…

JUC并发编程学习笔记(六)线程池及分支合并框架

10 ThreadPool 线程池&#xff08;重点&#xff09; 10.1 线程池简介 回顾以前的连接池概念 连接池是创建和管理一个连接的缓冲池的技术&#xff0c;这些连接准备好被任何需要它们的线程使用 线程池&#xff08;英语&#xff1a;thread pool&#xff09;&#xff1a;一种线程…

实时数仓,为什么不可代替?

什么是实时数据仓库&#xff1f;它有哪些不可替代之处&#xff1f; 大数据时代中&#xff0c;数据仓库解决了商业智能分析过程中的数据管理问题&#xff0c;但是存在烟囱式、冗余高的弊端 随着商业智能的兴起和数据时代的到来&#xff0c;越来越多的企业开始汇总、整合和分析自…

ArcGIS基础实验操作100例--实验62点、线、面状符号

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验62 点、线、面状符号 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

C/C++中二级指针传递参数【个人遇到内存值发生改变现象的记录及相关修正方法】

目录 0、前言 1、二级指针传参奇怪现象 2、分析 3、解决方法 0、前言 在c/c中&#xff0c;时常会使用到主调函数通过参数去获取被调函数中的数值情况。针对这种情况&#xff0c;我前面也写过C/C主调函数从被调函数中获取&#xff08;各种类型&#xff09;数据内容方式的梳理…

【ONE·R || 两次作业(一):R基础数据处理】

总言 两次作业汇报&#xff1a;其一。    文章目录总言1、作业一&#xff1a;1.1 、任务一&#xff1a;各项数据建立1.2 、任务二&#xff1a;去除缺失值1.3 、任务三&#xff1a;返回性别为女生&#xff0c;年龄<20的学生及成绩1.4、 任务四&#xff1a;统计性别为女生&a…

【Python百日进阶-数据分析】Day149 - plotly直方图:go.histogram()

文章目录4.2 利用 go.Histogram 的直方图4.2.1 基本直方图4.2.2 归一化直方图4.2.3 水平直方图4.2.4 叠加直方图4.2.5 堆叠直方图4.2.6 风格直方图4.2.7 直方图条形文本4.2.8 累积直方图4.2.9 指定聚合函数4.2.10 自定义分箱4.2.11 在直方图之间共享 bin4.2.12 按类别顺序排序直…

深度学习(一)-环境安装

前言&#xff1a; 最近电脑重装了下系统&#xff0c;然后所有环境啥的都得重新配置一遍&#xff0c;刚好趁着这个时间记录下整个环境的配置过程 注意&#xff1a;本文记录的仅为window系统的配置过程! 一、Anaconda安装及相关配置 Anaconda下载地址&#xff0c;根据需要选择需…

TypeScript 中 Class incorrectly implements interface 错误

当一个类在没有指定接口上定义的所有属性和方法的情况下实现接口时&#xff0c;会发生错误“Class incorrectly implements interface”。 要解决该错误&#xff0c;需要确保定义并键入接口的所有必需属性和方法。 下面是产生上述错误的示例代码 interface Employee {id: num…

Linux学习记录——유 gcc/g++基础知识

文章目录一、程序翻译二、gcc使用1、-o2、预处理-E3、编译-S4、汇编-c5、链接三、库四、库的部分实际操作五、Linux项目自动化构建工具 make/Makefile1、规则一、程序翻译 C语言中&#xff0c;写出代码后&#xff0c;编译器会经过四个阶段才会生成可执行文件。 预处理&#x…

计算数组中元素的加权平均值 numpy.average()

【小白从小学Python、C、Java】【计算机等级考试500强双证书】【Python-数据分析】计算数组中元素的加权平均值numpy.average()[太阳]选择题对于以下python代码最后输出的结果是?import numpy as npa np.array([1, 2, 3, 4])print("【显示】a")print(a)print("…

如何进行Java 单元测试

什么是单元测试 维基百科中是这样描述的&#xff1a;在计算机编程中&#xff0c;单元测试又称为模块测试&#xff0c;是针对程序模块来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中&#xff0c;一个单元就是单个程序、函数、过程等&#xff1b;…

架构师课程笔记day04——Nginx

大纲 1.从单体到集群过渡 2.Nginx 2.1什么是nginx 2.2常见服务器 2.3nginx在架构中所处位置 2.4使用率&#xff0c;性能&#xff0c;市场占有率等信息 2.5正反向代理啥意思 正向代理 反向代理 示例 2.6安装步骤 Nginx安装步骤 常用命令等 2.7请求链路 2.8进程模型 通用模型 …

JS面向对象基础(原型链、构造函数、new关键字、寄生组合继承、对象元编程)

这篇文章将简单介绍面向对象的基本概念&#xff0c;以及JS语言是如何支持面向对象这种编程范式的&#xff0c;最后还会讲解一些对象元编程的基础知识。通过阅读这篇文章&#xff0c;你可以了解JS中的原型链机制&#xff0c;new和构造函数的原理、寄生组合继承的实现以及对象元编…