C++初阶:初识C++

news2024/11/25 20:17:30

目录

  • 1. 前言:C++ 与 C语言
  • 2. C++对于C语言语法的完善与补充
    • 2.1 命名冲突与命名空间
      • 2.1.1 命名空间的定义
      • 2.1.2 调用方式
    • 2.3 补充:流的概念
    • 2.4 缺省参数
      • 2.4.1 缺省参数的使用
    • 2.5 函数重载
      • 2.5.1 什么是函数重载
      • 2.5.2 函数重载的使用
      • 2.5.3 特殊情况:函数重载与缺省参数的冲突
    • 2.6 引用与指针
      • 2.6.1 什么是引用
      • 2.6.2 引用的使用方式
      • 2.6.3 const常引用
      • 2.6.4 引用的应用场景
      • 2.6.5 补充
    • 2.7 内联函数
      • 2.7.1 什么是内联函数
      • 2.7.2 内联函数的调用机制
      • 2.7.3 C++与宏
    • 2.8 关键字auto
    • 2.9 范围for
    • 2.10 指针空值nullptr

1. 前言:C++ 与 C语言

  1. 相对于C语言面向过程的编程语言,C++在继承C的基础上进行发展与补足,为C语言添加了面向对象方面的内容(类与对象,继承多态,模板)
  2. 面向对象与面向过程:如果将编程比作洗衣服,那么面向过程的编程就好比我们自己一步一步的进行衣物浆洗(接水,放入洗衣液,浸泡,手搓),而面向对象编程就是洗衣机,我们只用将衣服放入,倒水倒洗衣液,具体的细节我们无需关系。总的来说,C关心得是过程,而C++只用关注对象与对象及其他们的关系。

2. C++对于C语言语法的完善与补充

2.1 命名冲突与命名空间

在C语言的学习中,我们了解,在一个变量或函数的声明周期内,与它同一作用域中,不能创建与其同名的变量或函数。这在很多时候导致了不便,对于代码的可读性与灵活性也存在一定影响,而在C++中引入了命名空间这一新语法很好的解决了这一问题,接下来就让我们进行这方面的学习。

2.1.1 命名空间的定义

  1. 定义方式:关键字namespace后加空间名
  2. 作用:
    <1>正常变量的作用范围是它声明周期内的整个作用域,而命名空间就像是一个院子,将其空间内变量函数等封装了起来。
    <2> 正常检索下不会进入命名空间内,只有使用时指定才会在进入其中检索。
    <3> 命名空间内的变量,函数,自定义类型等与命名空间外的同名变量,函数,自定义类型不冲突。

定义方式:

namespace space1//[自定义名称]
{
	//变量。。。。
	int a;
	//函数。。。。
	int Add(int num1, int num2)
	{}
	//自定义类型。。。。
	typedef struct Node
	{}Node;
}

补充(命名空间可以嵌套使用):

namespace space1
{
	namespace space2
	{
		int a;
	}
} 

2.1.2 调用方式

调用方式1:(指定命名空间)

//调用命名空间内的资源
//变量
space::a = 1;
//函数
int ret = space::Add(1, 2);
//自定义类型
space1::Node node1;

//嵌套命名空间的调用方式
space1::space2::a = 1;

调用方式2:(打开命名空间)

//打开命名空间,打开命名空间后可以不使用后缀访问其内资源
using namespace space;

using namespace space1::space2;

调用方式3:(将单个命名空间中的资源引入)

//引入space1空间中的a
using space1::a;
a = 2;

using space1::space2::a;

补充:

C++库中有自己的命名空间,比如std,是C++头文件<iostream>中的命名空间,其内部有一些很重要的资源。示例如下:

  1. 注:C++中的头文件不带.h,以与C中的头文件做区分
using namespace std;

//cout为继承ostream类型的对象
// << 为流插入操作符
//endl为行结束标志
cout << "hello world" << endl;
  1. 语句意义:向cout中插入信息,将信息插入到显示器上
  2. <<流插入操作符

2.3 补充:流的概念

  1. 因为有各种各样的硬件设备,它们之间的组成与结构不同,为了方便各个硬件间的协同工作,我们引入流的概念。
  2. 将电脑中的信息理解为一股有方向的流,我们不关心信息交换的具体方式,只理解为有一条条信息组成的"河流"从源头设备流入向目标设备。
  3. 流插入操作符的意义即为,将指定的信息插入到指定设备中去。(cout标准输出对象:控制台,cin标准输入对象:键盘)
int num1 = 0;
//从键盘上读取数据将其存放入变量num中
cin >> num1;

int num2, num3;
//可连续读取
//回车或空格间隔
cin >> num2 >> num3;

//可连续插入
cout << num1 << ' ' << num2 << ' ' << num3 << endl;

2.4 缺省参数

2.4.1 缺省参数的使用

  1. 我们在创建定义函数时,往往要给函数定义参数。带有参数的函数,当我们调用时传参不可缺漏。
  2. 而在C++中对于函数参数添加了新的内容,使得这一定则有了新的补充,方便了我们的日常使用
  3. 在C语言程序中,函数参数的传递是不可省略的,否则必将报错 ,C++中在传参中有时可以省略,具体规则如下:

全缺省:

函数参数都赋予缺省值,方式如下:

void Print(int a  = 0, int b = 0, int c = 0)
{
	cout << a << ' ' << b << ' ' << c << endl;
}

半缺省:

函数参数赋予部分缺省值,方式如下:

  1. 注1:缺省值的赋予不可中断不连续
  2. 注2:缺省值的赋予必须从第一个参数开始,不可以跳过第一个参数
//示例1:(正确)
void Print(int a = 0, int b = 0, int c)
{
	cout << a << ' ' << b << ' ' << c << endl;
}

//示例2:(错误)
void Print(int a = 0, int b, int c = 0)
{
	cout << a << ' ' << b << ' ' << c << endl;
}

//示例3:(错误)
void Print(int a, int b = 0, int c = 0)
{
	cout << a << ' ' << b << ' ' << c << endl;
}

2.5 函数重载

2.5.1 什么是函数重载

编程习惯上,我们常常说 “名称即含义”,因此,函数名也会简单概括函数的功能,使得代码的可读性大大提高。

//示例1:
void swap1(int* num1, int* num2)
{
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}

void swap2(char* str1, char* str2)
{
	char tmp = *str1;
	*str1 = *str2;
	*str2 = tmp;
}

//示例2:
int Add1(int num1, int num2)
{
	return num1 + num2;
}

int Add1(int num1, int num2, int num3)
{
	return num1 + num2 + num3;
}

可是,随着代码量的提高,很多函数都会具有类似的功能,可是细节不同,参数类型不同此时,此时函数的命名就会变得非常繁琐与麻烦,无法很好的在场景中应用。因为存在这一问题,C++添加了函数重载的内容。

函数重载与编译器的函数名修饰规则:

在C/C++中,一份程序想要运行要经历预处理,编译,汇编,链接,这几个阶段。当程序编译运行时,检测到调用的函数,在调用处是没有函数定义的,所以就要进行项目内各个文件的链接合并,在符号表中查询函数名并调用相应的函数地址。

  1. C语言中符号并表中只存有简单的函数名,当存在同名函数时编译器无法识别。
  2. C++中会对编译链接时会对函数名进行,下面简述Linux操作系统下g++的函数名修饰规则,[_Z] + [函数名长度] + [函数名首字母] + [函数类型首字母]

2.5.2 函数重载的使用

两个同名函数之间是否构成重载,只与参数类型,参数个数有关,与返回值无关。

参数类型不同(构成):

//构成重载
void swap(int* left, int* right)
{
	int tmp = *left;
	*left = *right;
	*right = tmp;
}

void swap(char* left, char* right)
{
	char tmp = *left;
	*left = *right;
	*right = tmp;
}

//调用方式:
int a = 10;
int b = 20;
swap(&a, &b);

char c1 = 'a';
char c2 = 'b';
swap(&c1, &c2);

参数个数不同(构成):

int Add(int nums1, int nums2)
{
	return nums1 + nums2;
}

int Add(int nums1, int nums2, int nums3)
{
	return nums1 + nums2 + nums3;
}

//调用方式:
cout << Add(10, 20) << endl;

cout << Add(10, 20, 30) << endl;

参数数量与类型相同,返回值不同(不构成):

int f()
{
	return 10;
}

void f()
{
	cout << 10 << endl;
}

2.5.3 特殊情况:函数重载与缺省参数的冲突

//记作Print1
void Print(int a = 0)
{
	cout << a << endl;
}

//记作Print2
void Print()
{
	cout << 0 << endl
}

上述情况下,Print1的缺省调用与Print2的调用具有相同的语句,编译无法处理会进行报错,在编写代码的过程中,不要进行如上操作。

2.6 引用与指针

  1. 在C语言的学习中,我们知道在对函数进行传参时,我们正常情况下向函数传递的只是参数的拷贝,如果我们想要在函数内对参数进行操作更改,我传参时就需要给函数传递参数的指针,再于函数内部对参数地址解引用,然后再对参数本身进行操作。
  2. 在C++中,我们有了可以简化这一过程的新增语法操作,“引用”,接下来就让我们对其进行学习。

2.6.1 什么是引用

引用,我们可以从语法层面将其简单理解为,对一个已经存在的元素"取别名",取名后新的名称也同样代表着原本的那个元素,对别名操作同样会对参数造成影响,两者的区别只有名称上的不同。

int a = 10;
int& b = a;

b++;
cout << a << endl;

在这里插入图片描述

2.6.2 引用的使用方式

定义方式:[参数类型]& 变量别名 = 变量

  1. 注:引用必须进行初始化,否则会发生报错
  2. 注:一个变量可以取多个别名,即被多次引用
  3. 注:引用一个变量后,就无法再引用其他的变量
int a = 10;

//定义方式
int& b = a;

//报错,必须初始化
int& c;

2.6.3 const常引用

  1. C语言中,我们学习过const修饰变量,const修饰的变量具有常属性,而具有常属性的变量无法被修改。
  2. 在引用中,const修饰的变量我们正常情况下无法正常引用,需要对引用也进行const修饰才能正常引用,此种别名也具有常性不能被修改。
//常变量
const int a = 10;
//常引用
const int& b = a;
  1. 因为常引用只读不改的特性,所以它也可以直接引用常量
const int& b = 10;
  1. 常引用可以引用变量,但引用不可以引用常变量(权限可以缩小不能放大)
  2. 跨类型的常饮用同样可能会导致数据精度的丢失
double c = 3.14;
//精度丢失
const int& d = c;
 //3

2.6.4 引用的应用场景

  1. 作参数
void swap(int& num1, int& num2)
{
	int tmp = num1;
	num1 = num2;
	num2 = tmp;
}
  1. 做返回值
int& Add(int num1, int num2)
{
	static int sum = 0;
	sum = num1 + num2;
	
	return sum;
}
  1. 引用做返回值,源变量的销毁(源变量的声明周期仅为函数体内,随着函数调用结束,变量销毁)
int& Add(int num1, int num2)
{
	int sum = num1 + num2;
	
	return sum;
}

//err
int ret = Add(10, 20);

2.6.5 补充

  1. 值返回比引用返回的效率低,值返回会在返回过程中创建一个中间变量,而引用则是直接返回数据本身。
  2. 引用与指针的区别:
    <1> 在概念上,引用是定义了一个变量的别名,而指针是存储了变量的地址
    <2> 在初始化时,引用必须进行初始化,而指针可以不初始化
    <3> 指针存在NULL指针,而引用不存在空引用
    <4> 引用在初始化引用一个目标后,后续不可再更改引用其他目标,而指针可以
    <5> 引用的大小是引用目标本身的大小,而指针大小只会是4/8字节
    <6> 引用加1是对本身元素加1,而指针则是加一步(指针步长由指针类型决定)
    <7> 使用上,指针需要解引用才能对指向对象进行操作,引用我们则是可以直接进行操作(具体细节由编译器执行)
    <8> 有多级指针,但没有多级引用
    <9> 引用比指针更加安全

2.7 内联函数

2.7.1 什么是内联函数

  1. 在编写程序时,我们经常会进行函数的定义,将需要的功能模块化从而优化代码的结构,提高代码的可读性。
  2. 可是有些时候,编写的函数非常短小,为此再专门开辟栈帧来调用,当此函数被多次反复调用时反而会很大程度上影响程序的效率,因此我们引入内联函数。

内联函数的定义方式:在函数名前加上关键字inline

inline int Add(int num1, int num2)
{
	return num1 + num2;
}

2.7.2 内联函数的调用机制

  1. 内联函数不会再去额外开辟栈帧,而是将函数体内的语句在调用处直接展开,然后依次执行
  2. 我们对于函数的inline声明,编译器并不一定会进行执行,此行为只相当于我们给编译器提建议,具体如何操作由编译器考量(当函数过于复杂,语句数量超过一定限度,如:75)
  3. 内联函数可能会导致目标文件内代码量的膨胀
  4. 内联函数不建议使用定义与声明分离的操作,因为内联函数会在条用处直接展开,声明展开后就无法找打定义处的函数地址

2.7.3 C++与宏

  1. 在C语言中我们学习过宏,它的存在可以让增强了代码的复用性,提升了代码效率。可同时他也有着不可忽视的缺点,它的替换机制为我们的调试代码很大的不方便,维护起来及其不方便,同时也没有类型检查使得安全下降,针对他的两个使用场景C++中有了其的上位选择(有同时优点的同时,规避了缺点)
  2. 使用场景:
    <1> 短小函数 :内联函数
    <2> 替换常量:枚举

枚举示例:

//宏
//#define day 0

//枚举可调试
enum Day
{
	Mon,
	Tues,
	Feb,
	Thu,
	Fir,
	Sat,
	Sun
}

Day day = Tue;
cout << "today is " << day << endl;

2.8 关键字auto

  1. 使用场景:auto可以自动推导处变量的类型,当参数类型过长,或复杂易错时我们可以用auto关键字代替。
  1. 可搭配指针与引用使用,具体如下:
int i = 10;

 auto a = &i;
 auto* b = &i;
 auto& c = i;
 
 //得到变量的类型
 cout << typeid(a).name() << endl;
 cout << typeid(b).name() << endl;
 cout << typeid(c).name() << endl;
 
 *a = 20;
 *b = 30;
 c = 40;
  1. auto不可作为函数参数,无法得出函数的参数类型
//err
int Add(auto num1, auto num2)
{
	return num1 + num2;	
}
  1. auto无法直接定义数组
//err
auto arr[] = {1,2,3,4,5,6};

2.9 范围for

在C语言的逻辑for语句中,我们想要利用其进行数组的遍历时,必须要创建一个中间变量作为下标来进行元素的遍历,而范围for只需要给定需遍历数组即可,语法上更为方便简洁,具体如下:

int arr[] = {1,2,3,4,5,6};
//普通for循环
int i = 0;
for(i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
	cout << arr[i] << endl;
}

//范围for
for(auto e : arr)
{
	cout << e << endl;
}
  1. 范围for中的变量只是临时拷贝,对其的更改无法直接影响数组,需要指定变量类型为引用才可对值进行更改
for(auto e : arr)
{
	e *= 2;
}

for(auto e : arr)
{
	cout << e << endl;
}

for(auto& e : arr)
{
	e *= 2;
}
  1. 在后续的类与对象中我们会了解到其与迭代器的关系(实为傻瓜式的替换)

2.10 指针空值nullptr

在C语言中,我们查看源文件会发现NULL是0的宏替换,因为此种定义方式,其可能会在使用中造成如下的一些错误。

void f(int* p)
{
    cout << "int*" << endl;
}

void f(int p)
{
    cout << "int" << endl;
}

f(NULL);

运行结果:
在这里插入图片描述

在C++中,对这一缺漏有了补足,C++中新增空指针为nullptr,相当于(void)0*。

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

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

相关文章

七、链表问题(上)

160、相交链表&#xff08;简单&#xff09; 题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个…

如何采集京东搜索页面商品的销量、价格数据?

这段Python代码旨在从京东网站上获取商品信息&#xff0c;包括评论数量和评论的关键词&#xff0c;以便进行进一步的分析。该程序分析并模拟了京东的JavaScript请求&#xff0c;以获取动态加载的评论数据。 代码都测试验证过都能正常跑通&#xff0c;实现效果&#xff0c;由于…

图像处理与视觉感知---期末复习重点(1)

文章目录 一、概述二、图像处理基础2.1 视觉感知要素2.2 像素间的一些基本关系2.2.1 相邻像素2.2.2 连通性2.2.3 距离度量 2.3 基本坐标变换2.4 空间变换与灰度值 一、概述 1. 图像的概念及分类。  图像是用各种观测系统以不同形式和手段观测客观世界而获得的、可以直接或间接…

C++——string类

前言&#xff1a;哈喽小伙伴们&#xff0c;从这篇文章开始我们将进行若干个C中的重要的类容器的学习。本篇文章将讲解第一个类容器——string。 目录 一.什么是string类 二.string类常见接口 1.string类对象的常见构造 2.string类对象的容量操作 3. string类对象的访问及遍…

【DevSecOps】2024 年需要警惕的 10 大 Web 应用程序安全威胁

【DevSecOps】2024 年需要警惕的 10 大 Web 应用程序安全威胁 由于 2023 年出现了许多创新,我们之前所了解的许多内容都发生了巨大变化;随着其中一些重大变化,威胁格局也发生了转变,一些旧威胁减少了,一些新威胁增加了。 技术每天都在不断变化,当我们谈论技术和相关威胁…

MetaQTL:元分析基础教程

MetaQTL 基础知识 在遥远的海洋中&#xff0c;每个岛屿都藏着无尽的宝藏&#xff0c;而探险家们争相寻找地图&#xff0c;以期揭开宝藏的秘密。 现实世界中&#xff0c;我们的基因组就像那片广阔的海洋&#xff0c;而隐藏在其中的宝藏就是控制我们身高、健康、甚至是我们性格的…

Netty之WebSocket协议开发

一、WebSocket产生背景 在传统的Web通信中&#xff0c;浏览器是基于请求--响应模式。这种方式的缺点是&#xff0c;浏览器必须始终主动发起请求才能获取更新的数据&#xff0c;而且每次请求都需要经过HTTP的握手和头部信息的传输&#xff0c;造成了较大的网络开销。如果客户端…

git 命令怎么回退到某个特定的 commit 并将其推送到远程仓库?

问题 不小心把提交的名称写错提交上远程仓库了&#xff0c;这里应该是 【029】的&#xff0c;这个时候我们想回到【028】这一个提交记录&#xff0c;然后再重新提交【029】到远程仓库&#xff0c;该怎么处理。 解决 1、首先我们找到【028】这条记录的提交 hash&#xff0c;右…

微信小程序开发系列(八)·微信小程序页面的划分以及轮播图区域的绘制和图片的添加

目录 1. 划分页面结构 2. 轮播图区域绘制 3. 轮播图图片添加 1. 划分页面结构 最终我们想达到如下效果&#xff1a; 其页面分为四层结构&#xff0c;因此我们需要配置四块view&#xff0c;代码如下&#xff1a; <!-- view 小程序提供的容器组件&#xff0c;可以当成…

《ChatGPT原理与架构:大模型的预训练、迁移和中间件编程 》

OpenAI 在 2022 年 11 月推出了人工智能聊天应用—ChatGPT。它具有广泛的应用场景&#xff0c;在多项专业和学术基准测试中表现出的智力水平&#xff0c;不仅接近甚至有时超越了人类的平均水平。这使得 ChatGPT 在推出之初就受到广大用户的欢迎&#xff0c;被科技界誉为人工智能…

zabbix监控中间件服务

zabbix监控Nginx 自定义nginx访问量的监控项&#xff0c;首先要通过脚本将各种状态的值取出来&#xff0c;然后通过zabbix监控。找到自定义脚本上传到指定目录/etc/zabbix/script/ 在zbx-client客户端主机操作 #创建目录&#xff0c;然后将脚本上传到该目录mkdir /etc/zabbix/…

7,图像镜像变换

水平镜像就是x图像宽度-原来的x&#xff0c; 垂直镜像就是y图像高度-原来的y void CDib::Mirror_Horizontal() { //指向原图像指针 LPBYTE lpSrc; LPBYTE p_data GetData(); //指向复制区域的指针 LPBYTE lpDst; //图像的宽和高 LONG width GetWidth(); LONG height GetHei…

备战蓝桥杯————二分查找(二)

引言 在上一篇博客中&#xff0c;我们深入探讨了二分搜索算法及其在寻找数组左侧边界的应用。二分搜索作为一种高效的查找方法&#xff0c;其核心思想在于通过不断缩小搜索范围来定位目标值。在本文中&#xff0c;我们将继续这一主题&#xff0c;不仅会回顾二分搜索的基本原理&…

【C++专栏】C++入门 | 命名空间、输入输出、缺省参数

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;C专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家 点赞&#x1f44d;收藏⭐评论✍ C入门 | 命名空间、输入输出、缺省参数 文章编号&#xff1a;C入门 / 0…

Java agent技术的注入利用与避坑点

什么是Java agent技术&#xff1f; Java代理&#xff08;Java agent&#xff09;是一种Java技术&#xff0c;它允许开发人员在运行时以某种方式修改或增强Java应用程序的行为。Java代理通过在Java虚拟机&#xff08;JVM&#xff09;启动时以"代理"&#xff08;agent…

react native中如何使用webView调用腾讯地图选点组件

react native中如何使用webView调用腾讯地图选点组件 效果示例图代码示例备注 效果示例图 代码示例 import React, {useEffect, useRef, useState} from react; import {Modal, StyleSheet} from react-native; import {pxToPd} from ../../common/js/device; import {WebView…

使用PDFBox封装一个简单易用的工具类快速生成pdf文件

文章目录 一、PDFbox说明1、坐标2、线3、图4、字5、字体加载6、jfreechart图表转字节数组7、依赖二、PDFbox样式1、文字颜色2、线颜色3、线样式三、工具类边框样式对齐样式表行列图片列pdf工具类测试方法四、效果图一、PDFbox说明 1、坐标 文档左下角为坐标原点,x轴向右从0增…

Cluade3干货:超越GPT,模型特点分析+使用教程|2024年3月更新

就在刚刚&#xff0c;Claude 发布了最新的大模型 Claude3&#xff0c;并且一次性发布了三个模型&#xff0c;分别是 Claude 3 Haiku&#xff1a;&#xff08;日本俳句 &#xff09;Claude 3 Sonnet&#xff08;英文十四行诗&#xff09;Claude 3 Opus&#xff08;古典乐作品集…

HarmonyOS NEXT应用开发案例——滑动页面信息隐藏与组件位移效果

介绍 在很多应用中&#xff0c;向上滑动"我的"页面&#xff0c;页面顶部会有如下变化效果&#xff1a;一部分信息逐渐隐藏&#xff0c;另一部分信息逐渐显示&#xff0c;同时一些组件会进行缩放或者位置移动。向下滑动时则相反。 效果图预览 使用说明 向上滑动页面…

Vue:双token无感刷新

文章目录 初次授权与发放Token&#xff1a;Access Token的作用&#xff1a;Refresh Token的作用&#xff1a;无感刷新&#xff1a;安全机制&#xff1a;后端创建nest项目AppController 添加login、refresh、getinfo接口创建user.dto.tsAppController添加模拟数据 前端Hbuilder创…