当前位置: 首页 > article >正文

C++修炼之路:初识C++

        Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!

我的博客:<但凡.

我的专栏:《编程之路》、《数据结构与算法之美》、《题海拾贝》

欢迎点赞,关注!

引言

        ‌C++‌,通常被称为“C加加”,是一种由Bjarne Stroustrup在1983年开发的通用编程语言。它是由C语言扩展升级而来,支持面向对象程序设计、过程化程序设计等多种编程范式。‌

        C++的应用领域服务器端、游戏(引擎)、机器学习引擎、音视频处理、嵌入式软件、电信设备、金融 应用、基础库、操作系统、编译器、基础架构、基础工具、硬件交互等很多方面都有。

        本篇文章作为c++基础教学的第一篇,将带大家认识和简单使用c++。


1、C++的第一个程序

        万物始于hello world.现在我们来用c++写一个hello world:

#include<iostream>
using namespace std;
int main()
{
	cout << "hello world" << endl;

	return 0;
}

        我们来分析一下这个程序:首先和C语言一样,上来先包括一个头文件。这里我们包过的头文件是iostream库,意思是输入输出流。里面包含着c++最常用的输入和输出

        接下来一行叫展开命名空间。只有展开的这个明明空间我们的iostream库里的函数才能随便使用。当然了至于什么是命名空间以及为什么要展开我们下文再谈。

        下面一行和我们的c语言一样,都是int main。这里的int main和C语言中的一样就不过多赘述了。

        接下来一行是输出hello world这个字符串。cout是iostream库中提供的输出函数。用法就是cout<<输出内容。后面的endl是换行(endline),但和C语言里面的\n不用,endl是一个函数

2、命名空间

2.1命名空间的定义及使用

        命名空间namespace存在的意义是为了解决命名冲突。在C语言中实现这个代码

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
 // 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数” 
 printf("%d\n", rand);
 return 0;
}

        会报错。报错的原因就是我们自己定的变量rand和C语言自带的库函数冲突了。这时候编译器就无法识别了。这其实是C语言的不足之处。而c++中的命名空间就完美的解决了这个问题。

        想想一下这个场景。小张和小王同时进行一个项目,但是他俩写的函数名有时候会相同,不如小张的加法函数叫test,小王的乘法函数叫test,那这时候都不用和系统自带的函数冲突了,两个人写的函数就已经冲突了。这个时候namespace的用处就来了。我们把小张和小王的代码写成下面这样:

#include<iostream>
using namespace std;
namespace mrZhang
{
	int test(int x, int y)
	{
		return x + y;
	}
}
namespace mrWang
{
	int test(int x, int y)
	{
		return x * y;
	}
}
int main()
{
	int a = mrZhang::test(1, 5);
	int b = mrWang::test(1, 5);
	cout << a << " " << b;
	return 0;
}

输出一下,分别是6和5,小张和小王的代码可以毫不冲突的正常使用了。

        其实命名空间本质上是定义出一个域,我们小张和小王各有一个域,那他们从自己的域里面调用自己的函数不就毫不冲突了吗?

        在调用的时候,我们只要用 空间名::函数名 这样的格式来调用。

        命名空间还可以进行嵌套,比如这样:

#include<iostream>
using namespace std;
namespace mrZhang
{
	int test(int x, int y)
	{
		return x + y;
	}
	namespace mrWang
	{
		int test(int x, int y)
		{
			return x * y;
		}
	}

}
int main()
{
	int a = mrZhang::test(1, 5);
	int b = mrZhang::mrWang::test(1, 5);
	cout << a << " " << b;
	return 0;
}

        输出结果仍然是6和5。

        命名空间中不止可以定义函数,也可以定义变量和自定义类型。这样的话你自己定义的变量也可以和别的同名变量毫不冲突了。

        另外在多文件中可以定义同名的命名空间。这样的话他们就会合成一个命名空间。

2.2命名空间的展开

        现在看我们第一个helloworld程序,第二行的using namespace std;就是展开命名空间。正常我们使用输入输出函数是这样的:

#include<iostream>
int main()
{
	std::cout << "hello world" << std::endl;

	return 0;
}

        当我们程序比较简单,不会出现冲突的命名的时候就可以把命名空间展开。

        比如平时的简单练习程序,或者算法题,我们就可以直接Using namespace std;把命名空间展开直接使用c++自带的函数。

        我们也可以只展开一个命名空间中的某个变量或函数,这样的话访问这个变量或函数就更简便了:

#include<iostream>
using namespace std;
namespace mrZhang
{
	int test(int x, int y)
	{
		return x + y;
	}
}
using mrZhang::test;
int main()
{
	int a = test(1, 5);

	cout << a;
	return 0;
}

3、缺省参数

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

        缺省参数又叫默认参数。

比如我们定义一个这样的函数:

int test(int x=2, int y=6)
{
	return x + y;
}

        我们调用这个函数但是不传入实参,返回结果就是8.

        如果再调用时我们传入实参1和2,那么返回值就是1+2=3。

需要注意三点:

        1、缺省参数必须从右往左给。比如上面的程序,我们只给x缺省参数但不给y缺省参数这样其实是不合法的。

        2、函数实参一定是从左往右给函数的。

        3、函数声明和定义分离时,不能在声明和定义中同时给缺省值。

比如这样,其实是不合法的:

#include<iostream>
using namespace std;

int test(int x = 1, int y = 2);
int main()
{
	int a = test();
	cout << a;
	return 0;
}
int test(int x = 1, int y = 2)
{
	return x + y;
}

        我们只能在声明中给,不能在定义中给。

4、函数重载

        在c++中允许出现同名函数,但是同名函数的返回值或者形参类型或形参个数必须有一个不同。在调用函数时,c++可以根据传入实参的类型自动选择正确的函数。比如这样:

#include<iostream>
using namespace std;

int test(int x , int y )
{
	return x + y;
}
double test(double x, double y)
{
	return x + y;
}
int main()
{
	double x = 1.5, y = 2.8;
	int a = test(1,2);
	double b = test(x, y);
	cout << a <<" "<< b ;
	return 0;
}

5、引用

5.1引用的介绍

        引用其实就是给我们已有的一个变量去别名。并不会开辟新的空间。它的使用格式是这样的:类型&引用别名=引用对象;

        就像每个人都有大名和乳名一样,我叫这两个名字其实指的人都是一个。比如这样:

int i = 5;
int& j = i;

        此时我们改变j就相当于改变了i。那这个东西有什么意义呢?回想我们在C语言阶段学习指针的时候,交换两个数的函数得用指针变量做形参。有了引用这个东西,我们就可以这样写交换函数

void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

        怎么样,是不是方便了很多呢?

        其实引用的底层也是指针。所以说通过引用我们能够改变原值。

5.2引用的特性

        1、引用必须在定义时初始化。比如int& a=0;这句代码其实是不合法的。

        2、一个变量可以有多个引用。

        3、引用一旦引用一个实体,再不能引用其他实体。

比如下面这串代码:

#include<iostream>
using namespace std;

int main()
{
	int a = 10;
	int& b = a;
	int c = 20;
	b = c;
	cout << &a <<" "<< &b <<" "<< &c << endl;
	cout << a <<" "<< b <<" "<< c << endl;
	return 0;
}

        我们进行了b=c的操作,只是把c的值赋值给了b,但并没有改变b的引用实例,正因此a和b地址是相同的。

5.3引用的使用

        引用在实践中主要是于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被 引用对象。

        引用传参我们已经介绍过了,现在我们介绍一下引用做返回值。

int STTop(ST& rs)
{
 assert(rs.top > 0);
 return rs.a[rs.top];
}
int main()
{
 ST st1;
 STInit(st1);
 STPush(st1, 1);
 STPush(st1, 2);
 STTop(st1)+=10;
 return 0;
}

        我们截取了一部分之前栈的操作,发现对于STTop(st1)+=10;这个操作是无法达到目的的。

我们想的是让栈顶的数据加上10,但是实际上栈顶的数据并没有改变。

        这是因为咱们返回的是一个值,相当于我们把原来的数拷贝出了他的值然后返回了,就算把这份拷贝的值加上10也无法改变原来的栈顶数据。而且实际上值的拷贝具有常性,根本就无法改变,导致这个程序报错。所以从哪个角度来说栈顶数据都无法被更改。

        但是我们如果是引用返回的话,就可以成功改变栈顶的值,因为我们是直接对栈顶这个区域进行的操作。 

5.4、const引用

        const对象必须用const引用,普通对象也可以用const引用,但普通引用引用不了const对象。       

        这涉及到权限的问题。普通对象是一个变量,可以被改变的,所以他的权限更低。而const对象不能被改变所以他的权限更高。普通引用引用const对象权限就放大了,所以编译器会报错。反过来const引用可以引用普通对象,因为权限是可以缩小的。

6、inline内联 

        由于C语言中宏函数设计的不足,c++中inline的诞生就是为了代替宏函数。

#include<iostream>
using namespace std;
inline int add(int x,int y)
{
	return x + y;
}
int main()
{
	cout << add(1, 5) << endl;

	return 0;
}

        对于短小的函数,inline操作会使函数在编译时展开,可以提高效率。但是如果这个函数过长就不适合使用内联了,过长的函数内联反而会降低时间,甚至,有的编译器防止用户内联过长的函数,就算内联了,也不会起内联的作用。

        注意,内联函数的定义和声明必须在同一个文件。

        好了,今天的内容就分享到这,我们下期再见!

 

 


http://www.kler.cn/a/579414.html

相关文章:

  • 【SegRNN 源码理解】【今天不水文系列】编码器部分理解
  • [java][OAuth2.0]OAuth2.0建表语句
  • 如何使用 GPT-4o 翻译播客声音
  • AI编程: 一个案例对比CPU和GPU在深度学习方面的性能差异
  • Nginx开启目录浏览功能时加密码的方法
  • Java 解决 TCP 粘包问题详解:原理与实战示例
  • 【flutter】TextField输入框工具栏文本为英文解决(不用安装插件版本
  • 爬虫案例十js逆向合肥滨湖会展中心网
  • 【大模型基础_毛玉仁】1.4 语言模型的采样方法
  • mac本地安装运行Redis-单机
  • 【前端】【组件】【vue2】封装一个vue2的ECharts组件,不用借助vue-echarts
  • MySQL创建数据库和表,插入四大名著中的人物
  • 深度学习与普通神经网络有何区别?
  • Ai大模型day02神经网络+深度学习
  • Agentic系统:负载均衡与Redis缓存优化
  • 刷题记录(LeetCode738 单调递增的数字)
  • Web3 的隐私保护机制:如何保障个人数据安全
  • Redis渐进式遍历数据库
  • rpc和proto
  • 【YOLOv12改进trick】多尺度大核注意力机制MLKA模块引入YOLOv12,实现多尺度目标检测涨点,含创新点Python代码,方便发论文