[一] C++入门

news2024/11/16 3:50:54

摘要:OOP(面向对象),namespace,cout and cin,缺省参数,函数重载,引用,内联函数,auto,范围 for,nullptr

20世纪80年代,计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。C++是基于C语言而 产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

A major design goal of C++ is to let programmers define their own types that are as easy to use as the built-in types.

——《C++ Primer》


1. 命名空间_namespace

namespace fantasy
{
	int a = 13;
	int l = 7;
	struct MyStructRB
	{
		int capacity;
		int size;
	}RB;
}


int main()
{
	int sum = fantasy::a + fantasy::l;

	fantasy::RB.size = 0;
	fantasy::RB.capacity = 0;

	return 0;
}

导入_why

Question:全局变量与局部变量冲突时,优先哪个?     

#include<stdio.h>

int num = 7;

int main()
{
    int num = 13;
    printf("%d",num);
    return 0;
}

Answer:局部变量,因为查找的顺序是:先局部 ⇢ 再全局(output: 13

  • 为了解决变量名冲突的问题,命名空间应运而生

namespace_what

  • namespace:C++关键字
  • [name_of_namespace]:: 域作用限定符(::) ,左操作数为 name_of_namespace ,意为在该命名空间的区域内查找变量,如果左操作数为空,则表示在全局查找。 

Rules_use

  1. 命名空间的名称不应有空格,错误示例:

  2. 同名的命名空间会被合并

  3. 命名空间支持嵌套
    namespace fantasy
    {
    	int a = 13;
    	int l = 7;
    	namespace RoundBottle
    	{
    		struct MyStructRB
    		{
    			int* array;
    			int size;
    		}RB;
    	}
    }
    
    int main()
    {
    	fantasy::RoundBottle::RB.size = 0;
    	fantasy::RoundBottle::RB.array = nullptr;
    	return 0;
    }

访问命名空间_declaration

  1. 指定命名空间访问
    std::cout << "Hello";
  2. 全局展开(日常练习中可以,项目中一般不会用全局展开):using namespace name_of_namespace;
    using namespace std;

2. C++ 输入&输出

  • stdC++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间
  • cout:输出流
  • cin:输入流
  • endl : 换行符(作用是换行并清空缓存区的数据
  • << 流插入运算符;>> 是流提取运算符;箭头方向可以理解为 “数据的流向 
#include <iostream>
using namespace std;

int main()
{
	int num = 0;
	// 可以自动识别变量的类型
	cin >> num;//把数据输入到 num 这个变量中进行储存
	cout << num << endl;//将num中储存的数据输出(到屏幕)
	return 0;
}

3. 缺省参数

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

示例_example

  • 缺省参数分为全缺省部分缺省
//全缺省
int Add(int x = 1, int y = 2)
{
	return x + y;
}

//部分缺省
int Sum(int x, int y, int z = 3)
{
	return x + y + z;
}

Rules_use

  1. 缺省参数不能跳跃,必须从左往右连续使用。错误示例
    #include<iostream>
    
    using namespace std;
    
    int Sum(int x = 1, int y, int z = 3)
    {
    	return x + y + z;
    }
    
    int main()
    {
    	int ret = Sum(1, 2);
    	cout << ret << endl;
    	return 0;
    }

    上述情况下,参数将无法确定传给谁,例如,参数“1”可能传给 x,也可能传给 y,因此这里出现了歧义,导致编译错误。同样的,上述代码也支持写成: ret = Sum( , 1, 2);

  2. 当函数的声明和定义分离时,缺省参数不能在声明和定义中同时出现,推荐在函数声明的时候给缺省参数(以下代码为错误示例
    //函数声明:
    int Add(int x = 1, int y = 2);
    
    //函数定义:
    int Add(int x = 1, int y = 2)
    {
    	return x + y;
    }

应用场景_apply

(举例:栈的初始化)

C:

// 初始化栈 
void StackInit(Stack* ps)
{
	STDataType* tmp = (STDataType*)malloc(4 * sizeof(STDataType));
	if (!tmp)
	{
		perror("malloc fail");
		exit(-1);
	}
	ps->_a = tmp;
	ps->_top = 0;
	ps->_capacity = 4;
}

CPP:

// 初始化栈 
void StackInit(Stack* ps, int initsize = 4)
{
	int* tmp = (int*)malloc(initsize * sizeof(int));
	if (!tmp)
	{
		perror("malloc fail");
		exit(-1);
	}
	ps->_a = tmp;
	ps->_top = 0;
	ps->_capacity = initsize;
}
  •  知道栈中最多存100个数据:

    • StackInit(&stack, 100);
  •  不知道栈中最多存多少数据:

    • StackInit(&stack);

4. 函数重载

函数重载 → 在同一个命名空间,且函数名相同,参数不同,体现为三种方式:

  1. 类型不同 e.g.function(int p);   function(double p);
  2. 个数不同 e.g.function(int p);   function(int p1 , int p2)
  3. (类型的)顺序不同 e.g.function(int p , double p);    function(double p , int p );

  • Question:仅返回值不同,能构成函数重载吗?

Answer:❌不能!函数调用的时候并不能指明返回值,当两个函数只有返回值的类型不同时,在尝试调用函数时无法确认将要调用哪个函数,将发生编译错误!返回值类型是否相同与函数构成重载不相关

函数重载是如何实现的?

首先,我们需要了解代码的编译过程:(这里简单描述一下)

  1. 预处理:头文件展开(注意:头文件展开不同于“命名空间展开”,头文件展开是把头文件的内容复制一份,“命名空间展开”是授权,允许在该空间内进行查找),宏替换,去注释,条件编译    (test.cpp → test.i)
  2. 编译:检查语法,生成汇编代码(指令级代码)(test.i  → test.s)
  3. 汇编:汇编代码 → 二进制机器码  (test.s → test.o)
  4. 链接:合并多个 .cpp/.c 文件,生成可执行文件 (test.o →test.exe/test.out)

在链接的环节会生成符号表,类似这样:

符号表
nameaddress
functionxxxxxxxxxx
main

xxxxxxxxxx

…………

链接的时候会通过 name 找到 address,函数地址是一个跳转指令,如果函数没有定义只有声明就不会有地址,这将发生链接错误。

  • C语言:直接用函数名充当符号表中的name,如下图。
  • C++:对函数名进行修饰,不同平台下的修饰规则不同(从下图的链接错误中,可以看见vs2022平台下对函数名的修饰)。

sum.

  1. C++对函数名进行了修饰,不同平台下的修饰规则不同
  2. 自动识别函数参数的类型 (会不会使运行速度变慢?👉不会,可能影响编译速度,但不影响运行速度)

5. 引用_References

#include<iostream>

using namespace std;

int main()
{
	int v1 = 13;
	int& v2 = v1;
	v2 = 7;
	cout << v1 << endl; //output:7
	return 0;
}

References_what

  • 引用 —— 一块存储空间的 “别名”
  • Type& variable_reference = variable_entity Type 后跟“”表示引用,variable_referencevariable_entity 表示的是同一块存储空间的不同名称。注意:variable_entity 应该与 Type 相符合。

Rules_use 

  1. 定义时必须初始化

  2. 一个变量可以有多个引用

    int main()
    {
    	int v1 = 13;
    	int& v2 = v1;
    	int& v3 = v1;
    	int& v4 = v1;
    
        int* p = &a;
        int*& pb = p;
    
    	return 0;
    }
  3. 引用在定义的时候必须初始化,因此只能引用一个实体,并且不能改变,否则会出现重定义

    int main()
    {
    	int v1 = 13;
    	int v2 = 7;
    	int& v3 = v1;
    	v3 = v2;//这是赋值,将v2的数据赋值给v3,同样的也是指v1
    
    	int& v3 = v2;//错误:重定义!!
    
    	return 0;
    }

常引用_const

  1. Type_const
    int main()
    {
        const int v = 13;
    	int& v1 = 13;//error
    
    	const int& v2 = 13;
        const int& v3 = v2;//correct
    	return 0;
    }
    

    上述代码中,“13” 的 Typeconst int,是只读不可修改的常量,在语句 int& v1 = 13 中本是上发生了权限放大,导致错误。v1 的是 Typeint,是可读可修改的变量。权限可以平移、缩小,但不能放大。

  2. 隐式类型转化_Type Conversion

    int main()
    {
    	int v_i = 0;
    	double& v_d = v_i;//error
        double v_d2 = v_i;//correct,同样发生了类型转化,但这只是赋值语句
    	return 0;
    }
    

    上述代码发生了隐式类型转化,int → double转化过程中会产生临时变量,临时变量具有属性!本质上来说这里仍发生了权限放大。

应用场景_apply

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

传引用的作用:①减少拷贝;②调用者可以修改该对象

1)做函数参数

传引用传参:输出型函数,形参的改变需要影响实参

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

int main()
{
	int x = 13, y = 7;
	Swap(x, y);

	cout << x << " " << y << endl;

	return 0;
}

2)做返回值:

传引用返回:函数的返回类型为一个引用

方式一:上图中的传引用返回可以直观的理解为下图中的代码 ⬇ ,_num 与 num 是同一块存储空间的不同名称,然后将这个空间中存储的数据赋值给变量 v 。warning:这样的行为是未定义的,因为 num 在出函数作用域时候被销毁,该存储空间被归还,再次访问这块空间会得到什么数据是不确定的。

方式二:“用引用来接收引用返回”,以下代码中,v 与 num 是同一块存储空间的不同名称,即表示同一块存储空间。

int& Count()
{
	int num = 0;
	++num;
	return num;
}

int main()
{
	int& v = Count();
	cout << v << endl;//ouput:1
	cout << v << endl;//ouput:随机值
	return 0;
}

  • 注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

引用和指针的区别⭐

语法上有区别,但底层实现本质上是相同的。

  • 引用概念上定义一个变量的别名,指针存储一个变量地址。引用不开空间,指针开空间。
  • 引用在定义时必须初始化,指针没有要求
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  • 没有NULL引用,但有NULL指针
  • 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  • 有多级指针,但是没有多级引用
  • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  • 引用比指针使用起来相对更安全
     

6. 内联函数_inline

当我们尝试实现一个可以进行加法运算的宏函数:以下 3 种写法都容易在使用 ADD宏函数的时候出现问题。

#define ADD(x,y) x+y
#define ADD(x,y) (x+y)
#define ADD(x,y) ((x)+(y));

//better
#define ADD(x,y) ((x)+(y))

宏函数的优点:

  1. 没有严格的类型 (Type) 检查;
  2. 针对频繁调用的简单函数,无需建立栈帧,提高了效率。

宏函数的缺点:

  1. 容易出错,语法坑很多;
  2. 不能调试(预处理阶段将被直接替换);
  3. 没有类型 (Type) 的安全检查。

内联函数展开_what

基于此,C++选择使用内联函数:以 inline 修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升了程序运行的效率。

为了在调试的时候看到内联函数的展开我们需要关闭优化:步骤如下列图片

  • 调用函数:
  • 内联函数:

内联函数的特性

  1. inline 是一种以空间换时间的做法。
  2. inline 内联说明只是向编译器发送一个请求,最终是否展开由编译器决定。 
  3. inline 不建议声明和定义分离,分离会导致链接错误。因为内联函数会被直接展开,不进符号表 ,链接就会找不到。

补充:关于代码膨胀

对于内联函数,如果该函数定义包含 100 行代码,调用该函数 100 次,如果被内联展开,最终会被编译成 100*100 行指令,导致代码膨胀。对于非内联函数,如果该函数定义包含 100 行代码,调用该函数 100 次,最终会被编译成 100+100 行指令。因此,体量过大的、调用频繁的函数不建议内联展开。


7. auto_关键字

功能:自动识别类型

int main()
{
	int i = 0;
	auto v = i;
	auto v2 = 0;
	return 0;
}

Rules_use

  1. 不能用在函数参数类型声明上:❌void func(auto p){……}
  2. 不能声明数组:❌auto array[] = { 0 };

补充:查看变量的类型 —— typeid

int main()
{
	auto v = 1;

	const type_info& vInfo = typeid(v);
	cout << vInfo.name() << endl;//output:int

	return 0;
}

8. 范围 for

int main()
{
	int array[] = { 1, 2, 3, 4, 5 };
	cout << array << endl;
	for (auto& var : array)
	{
		var *= 2;
		cout << &var << " " << var << endl;
	}

	for (auto num : array)
		cout << num << " ";
	//ouput:2 4 6 8 10
	//这里的var和num都是变量名,两者一不一样或取什么名字都是不影响的

	return 0;
}

注意:

  1. auto 一般和范围 for 搭配使用,但也可以指明具体的类型,for(int num : array) 类似的写法也是合法的,只是Type 应与 array 的类型相符合;
  2. 这里的 array 是能是数组名!错误示例如下,函数传参无法传递整个数组,这里实际上只是传过来数组首元素的地址。
    void func(int array[])
    {
    	for (auto e : array)//error
    	{
    		……
    		cout << e << endl;
    	}
    }
    
    int main()
    {
    	int array[] = { 1,2,3,4 };
    	for (auto e : array[0])//also error
    	{
    		……
    	}
    	return 0;
    
    }
    

9.nullptr

简而言之,NULL在C++中出现了错误,所以引入  nullptr 

#define NULL 0 //error
#define NULL ((void*)0)

nullptr 使用注意:

  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入 的。
  2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

END

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

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

相关文章

我和“云栖大会”的双向奔赴

目录 引言初次参加云栖大会云栖大会带来的技术风向标本届大会最强技术有哪些&#xff1f;云栖大会对我职业生涯的影响个人对未来云栖大会的期待和建议结语 引言 想必大家对“云栖大会”并不陌生&#xff0c;“云栖大会”作为国内最具规模和影响力的云计算盛会&#xff0c;每年…

flink状态不能跨算子

背景 在flink中进行状态的维护和管理应该是我们经常做的事情&#xff0c;但是有些同学认为名称一样的状态在不同算子之间的状态是同一个&#xff0c;事实是这样吗&#xff1f; flink状态在保存点中的存放示意图 事实上&#xff0c;每个状态都归属于对应的算子&#xff0c;也…

用红黑树封装mapset【C++】

目录 前言 一&#xff0c;定义 二&#xff0c;完善set&map比较 三&#xff0c;迭代器实现 operator operator-- operator[] 四&#xff0c;发现问题 解决 修改一&#xff1a; set封装层面 修改二&#xff1a;正向迭代器修改 下期预告&#xff1a; 哈希&#x…

DataxWeb安装部署及使用--真香警告

DataxWeb安装部署及使用–真香警告 文章目录 1.Datax简介1.1 Datax是什么&#xff1f;1.2 Datax的架构1.3 设计理念1.4 DataX3.0框架设计1.5 DataX3.0插件体系1.6 DataX3.0核心架构1.6.1 核心模块介绍1.6.2 DataX调度流程 2.DataxWeb简介2.1 DataxWeb是什么&#xff1f;2.2 Dat…

在Ubuntu上安装Redis并学习使用get、set和keys命令

目录 安装Redis切换到root用户搜索redis相关软件包安装redis修改配置文件重启服务器使用redis客户端连接服务器 get与set命令keys 安装Redis 我们在Ubuntu20.04上进行Redis的安装 切换到root用户 使用su命令&#xff1a; 在终端中&#xff0c;输入su并按回车键。然后输入roo…

【产品应用】一体化伺服电机在焊接设备中的应用

随着制造业的不断发展&#xff0c;焊接设备在许多领域都得到了广泛应用&#xff0c;如汽车制造、机械加工、钢结构等领域。为了提高焊接设备的性能和效率&#xff0c;许多厂家开始采用一体化伺服电机作为焊接设备的主要驱动部件。本文将介绍一体化伺服电机在焊接设备中的应用背…

Leetcode—485.最大连续1的个数【简单】

2023每日刷题&#xff08;十五&#xff09; Leetcode—485.最大连续1的个数 实现代码 int findMaxConsecutiveOnes(int* nums, int numsSize){int max 0;int i;int flag 0;int cnt 0;for(i 0; i < numsSize; i) {if(nums[i] 1) {if(flag 0) {flag 1;cnt 1;} else {…

python 实时读取文件数据生成折线图——Matplotlib

有时&#xff0c;为了方便看数据的变化情况&#xff0c;需要画一个动态图来看整体的变化情况。主要就是用Matplotlib库。 效果演示&#xff1a; 代码如下&#xff1a; import matplotlib.pyplot as plt import pandas as pdfilename data.log# 创建空的 DataFrame 对象 df …

开心打地鼠,Android小游戏开发

A. 项目描述 “开心打地鼠”是一款非常有趣的游戏&#xff0c;它能够帮助人们放松身心&#xff0c;同时也能够锻炼人们的智力。 “开心打地鼠”这款游戏的玩法非常简单&#xff0c;玩家需要在规定的时间内点击屏幕上出现的地鼠&#xff0c;每次点击都可以得到一定的分数。但是…

kafka动态认证 自定义认证 安全认证-亲测成功

kafka动态认证 自定义认证 安全认证-亲测成功 背景 Kafka默认是没有安全机制的&#xff0c;一直在裸奔。用户认证功能&#xff0c;是一个成熟组件不可或缺的功能。在0.9版本以前kafka是没有用户认证模块的&#xff08;或者说只有SSL&#xff09;&#xff0c;好在kafka0.9版本…

基于CMFB余弦调制滤波器组的频谱响应matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1、CMFB余弦调制滤波器组原理 4.2、CMFB调制过程 4.3、CMFB特点 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ......................…

【Linux】 unzip 命令使用

Unzip 是一个在 Unix 或类 Unix 系统&#xff08;例如 Linux&#xff09;中常用的命令行工具&#xff0c;用于解压缩由 ZIP 压缩算法创建的压缩文件。这个工具是开源的&#xff0c;并且通常在大多数的 Linux 发行版中默认安装。 语法 su [选项] [-] [USER [参数]...] unzip命令…

题号1575 C.难度排名 (并查集知识点)

题目&#xff1a; 样例1&#xff1a; 输入 1 4 3 1 4 2 4 3 4 输出 No 样例2&#xff1a; 输入 1 4 2 1 3 2 3 输出 Yes 思路&#xff1a; 这题&#xff0c;有两种情况是由矛盾的。 第一种情况&#xff1a;当前题号存在大于两个题号的相连&#xff0c;情况是矛盾的&#x…

python之pip常用指令

文章目录 pip show xxx 查看是否安装该 module

Git客户端软件 Tower mac中文版特点说明

Tower mac是一款Mac OS X系统上的Git客户端软件&#xff0c;它提供了丰富的功能和工具&#xff0c;帮助用户更加方便地管理和使用Git版本控制系统。 Tower mac软件特点 1. 界面友好&#xff1a;Tower的界面友好&#xff0c;使用户能够轻松地掌握软件的使用方法。 2. 多种Git操…

Numpy数值计算Numpy 进阶在线闯关_头歌实践教学平台

Numpy数值计算进阶 第1关 Numpy 广播第2关 Numpy 高级索引第3关 Numpy 迭代数组 第1关 Numpy 广播 任务描述 本关任务&#xff1a;给定两个不同形状的数组&#xff0c;求出他们的和。 编程要求 首先用 arange() 生成一个数组&#xff0c;然后用 reshape() 方法&#xff0c;将数…

Java入门篇 之 逻辑控制(练习题篇)

博主碎碎念: 练习题是需要大家自己打的请在自己尝试后再看答案哦&#xff1b; 个人认为&#xff0c;只要自己努力在将来的某一天一定会看到回报&#xff0c;在看这篇博客的你&#xff0c;不就是在努力吗&#xff0c;所以啊&#xff0c;不要放弃&#xff0c;路上必定坎坷&#x…

Windows 11 PowerShell 安装 jq 命令

本心、输入输出、结果 文章目录 Windows 11 PowerShell 安装 jq 命令前言jq 命令简介基本语法案例 Windows 11 PowerShell 安装 jq 命令使用 jq 格式化 curl 输出的 json弘扬爱国精神 Windows 11 PowerShell 安装 jq 命令 编辑&#xff1a;简简单单 Online zuozuo 地址&#xf…

微型计算机组成原理

1、微型计算机组成 一个传统微型计算机硬件组成如下图 CPU通过地址线、数据线和控制信号线组成的本地总线&#xff08;内部总线&#xff09;与系统其他部分进行数据通信。 地址线用于提供内存或I/O设备的地址&#xff0c;即指明需要读/写数据的具体位置&#xff1b;数据线用…

项目实战之安装依赖npm install

文章目录 nvmdeasync包和node-gyp报错deasync包node-gyp报错 前言&#xff1a;有些人看着还活着其实已经凉了好一会儿了。 初拿到项目 初拿到项目肯定是先看配置 package.json的啦&#xff0c;看看都需要安装什么依赖&#xff0c;然后 npm install,OK结束 皆大欢喜。 ————…