c++入门基础

c++入门的基础语法

write in front

作者:@ 不进大厂不改名
专栏:@ c++语言
作者简介:大一学生 希望能学习其同学和大佬的经验!
本篇博客简介:c++的入门级语法,为深入学习c++做铺垫。

1.c++的发展史及应用

1.1 c++是什么

C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。
1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

1.2 c++的发展

C with classes
类及派生类、公有和私有成员、类的构造和析构、友元、内联函数、赋值运算符
重载等
C++1.0
添加虚函数概念,函数和运算符重载,引用、常量等
C++2.0
更加完善支持面向对象,新增保护成员、多重继承、对象的初始化、抽象类、静
态成员以及const成员函数
C++3.0
进一步完善,引入模板,解决多重继承产生的二义性问题和相应构造和析构的处

C++98
C++标准第一个版本,绝大多数编译器都支持,得到了国际标准化组织(ISO)和美
国标准化协会认可,以模板方式重写C++标准库,引入了STL(标准模板库)
C++03
C++标准第二个版本,语言特性无大改变,主要:修订错误、减少多异性
C++05
C++标准委员会发布了一份计数报告(Technical Report,TR1),正式更名
C++0x,即:计划在本世纪第一个10年的某个时间发布
C++11
增加了许多特性,使得C++更像一种新语言,比如:正则表达式、基于范围for循
环、auto关键字、新容器、列表初始化、标准线程库等
C++14
对C++11的扩展,主要是修复C++11中漏洞以及改进,比如:泛型的lambda表
达式,auto的返回值类型推导,二进制字面常量等
C++17
在C++11上做了一些小幅改进,增加了19个新特性,比如:static_assert()的文
本信息可选,Fold表达式用于可变的模板,if和switch语句中的初始化器等
C++20
自C++11以来最大的发行版,引入了许多新的特性,比如:模块(Modules)、协
程(Coroutines)、范围(Ranges)、概念(Constraints)等重大特性,还有对已有
特性的更新:比如Lambda支持模板、范围for支持初始化等
C++23 制定ing

1.3 c++运用

1. 操作系统以及大型系统软件开发
所有操作系统几乎都是C/C++写的,许多大型软件背后几乎都是C++写的,比如:Photoshop、Office、JVM(Java虚拟机)等,究其原因还是性能高,可以直接操控硬件。
2. 服务器端开发
后台开发:主要侧重于业务逻辑的处理,即对于前端请求后端给出对应的响应,现在主流采用java,但内卷化比较严重,大厂可能会有C++后台开发,主要做一些基础组件,中间件、缓存、分布式存储等。服务器端开发比后台开发跟广泛,包含后台开发,一般对实时性要求比较高的,比如游戏服务器、流媒体服务器、网络通讯等都采用C++开发的。
3. 游戏开发
PC平台几乎所有的游戏都是C++写的,比如:魔兽世界、传奇、CS、跑跑卡丁车等,市面上相当多的游戏引擎都是基于C++开发的,比如:Cocos2d、虚幻4、DirectX等。三维游戏领域计算量非常庞大,底层的数学全都是矩阵变换,想要画面精美、内容丰富、游戏实时性搞,这些高难度需求无疑只能选C++语言。比较知名厂商:腾讯、网易、完美界、巨人网络等。
4. 嵌入式和物联网领域
嵌入式:就是把具有计算能力的主控板嵌入到机器装置或者电子装置的内部,能够控制这些装置。比如:智能手环、摄像头、扫地机器人、智能音响等。
谈到嵌入式开发,大家最能想到的就是单片机开发(即在8位、16位或者32位单片机产品或者裸机上进行的开发),嵌入式开发除了单片机开发以外,还包含在soc片上、系统层面、驱动层面以及应用、中间件层面的开发。
常见的岗位有:嵌入式开发工程师、驱动开发工程师、系统开发工程师、Linux开发工程师、固件开发工程师等。
知名的一些厂商,比如:以华为、vivo、oppo、小米为代表的手机厂;以紫光展锐、乐鑫为
代表的芯片厂;以大疆、海康威视、大华、CVTE等具有自己终端业务厂商;以及海尔、海信、格力等传统家电行业。
随着5G的普及,物联网(即万物互联,)也成为了一种新兴势力,比如:阿里lot、腾讯lot、京东、百度、美团等都有硬件相关的事业部。
5. 数字图像处理
数字图像处理中涉及到大量数学矩阵方面的运算,对CPU算力要求比较高,主要的图像处理算法库和开源库等都是C/C++写的,比如:OpenCV、OpenGL等,大名鼎鼎的Photoshop就是C++写的。
6. 人工智能
一提到人工智能,大家首先想到的就是python,认为学习人工智能就要学习python,这个是误区,python中库比较丰富,使用python可以快速搭建神经网络、填入参数导入数据就可以开始训练模型了。但人工智能背后深度学习算法等核心还是用C++写的。
7. 分布式应用
近年来移动互联网的兴起,各应用数据量业务量不断攀升;后端架构要不断提高性能和并发能力才能应对大信息时代的来临。在分布式领域,好些分布式框架、文件系统、中间组件等都是C++开发的。对分布式计算影响极大的Hadoop生态的几个重量级组件:HDFS、zookeeper、HBase等,也都是基于Google用C++实现的GFS、Chubby、BigTable。包括分布式计算框架MapReduce也是Google先用C++实现了一套,之后才有开源的java版本。

1.4 学习方法

1.多写笔记和博客
2.多练题,例如牛客网和Leetcode
3.多总结经验

2.命名空间

2.1命名空间的提出背景

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,
以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
下面展示一些 内联代码。

#include <stdio.h>
int main()
{
	int rand=1;
	printf("%d",rand);c语言中无法解决命名冲突的问题,
	                 因此c++引入了命名空间来解决这个
	                 问题
	return 0;
}

在这里插入图片描述
2.2命名空的定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员

hyh是命名空间的名字,一般开发中是用项目名字做命名空间名。

 1. 正常的命名空间定义
namespace hyh
{
	命名空间中可以定义变量/函数/类型
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}
2. 命名空间可以嵌套
 test.cpp
namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}
3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
ps:一个工程中的test.h和上面test.cpp中两个N1会被合并成一个
test.h
namespace N1
{
	int Mul(int left, int right)
	{
		return left * right;
	}
}

2.3命名空间的使用

namespace hyh
{
	命名空间中可以定义变量/函数/类型
	int a = 0;
	int b = 1;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}

命名空间的三种使用方法

1.加命名空间名称及作用域限定符

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

2.使用using将命名空间中某个成员引入

using hyh::a;
int main()
{
	printf("%d\n", N::a);
	return 0;
}

3.使用using namespace 命名空间名称 引入

using namespacce hyh;
int main()
{
	printf("%d\n", a);
	printf("%d\n", b);
	Sub(a,b);
	return 0;
}

命名空间的一般使用的情景

1.一般日常练习使用,不在乎命名污染,全展开使用,using namespace std.
2.项目中,不要全部展开。 指定访问或者展开常用.

3.缺省参数

3.1函数缺省概念

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

void Func(int a = 0)
{
	cout<<a<<endl;
}
int main()
{
	Func(); 没有传参时,使用参数的默认值
	Func(10);传参时,使用指定的实参
return 0;
}

3.2函数缺省分类
全缺省参数

void Func(int a = 10, int b = 20, int c = 30)
{
	cout<<"a = "<<a<<endl;
	cout<<"b = "<<b<<endl;
	cout<<"c = "<<c<<endl;
}

半缺省参数

void Func(int a, int b = 10, int c = 20)
{
	cout<<"a = "<<a<<endl;
	cout<<"b = "<<b<<endl;
	cout<<"c = "<<c<<endl;
}

注意

1. 半缺省参数必须从右往左依次来给出,不能间隔着给
2. 缺省参数不能在函数声明和定义中同时出现

Func(1, ,3);错误传参法
/a.h
void Func(int a = 10);
// a.cpp
void Func(int a = 20)
{}
注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该
用那个缺省值。

4.函数重载

4.1 函数重载:

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

4.2 函数重载的例子

参数类型不同

#include <iostream>
using namespace std;
1.参数类型不同
int Add(int a,int b)
{
	cout << "可以正常调用" << endl;
	return a + b;
}
double Add(double a, double b)
{
	cout << "可以正常调用" << endl;
	return a + b;
}
int main()
{
	1.参数类型不同
	int a = 1, b = 2;
	int ab=Add(a,b);
	double c = 1.0, d = 2.0;
	double cd=Add(c, d);

	return 0;
}

参数个数不同

#include <iostream>
using namespace std;
2.参数个数不同
void Add()
{
	cout << "可以正常调用" << endl;

}
void Add(double a)
{
	cout << "可以正常调用" << endl;
}
int main()
{
	2.参数个数不同
	Add();
	double c = 1.0, d = 2.0;
	Add(c);

	return 0;
}

参数类型顺序不同

#include <iostream>
using namespace std;
3.参数类型顺序不同
void Add(int a, char b)
{
	cout << "可以正常调用" << endl;
}
void Add(char a, int b)
{
	cout << "可以正常调用" << endl;
}
int main()
{
	3.参数类型顺序不同
	int a = 1;
	char b = '2';
	Add(a,b);
	Add(b,a);

	return 0;
}

4.3 函数重载背后的原理

为什么c++支持函数重载而c不支持这其中的道理要追溯到编译链接的问题这里简单说明一下,如果有兴趣请等待我的下一篇文章里面有详细说明。
一个程序要运行起来,要进行以下几个阶段:预处理、编译、链接。
一般一个项目是由多个头文件和源文件组成,编译后链接前而在执行链接时链接器要调用函数,可是目标文件中没有函数的地址,因为函数是在源文件中定义的,所以它的地址在生成的.o文件中,这时链接器要调用函数就会去源文件生成的.o文件的符号表中寻找函数的地址,然后链接到一起,(这里要提到编译后函数名会被修饰,而不同的环境的修饰规则不同)就在这时出现了问题因为c的编译后函数名的修饰名不发生改变c++在编译后函数名的修饰发生改变,就通过这种修饰后的函数名,就可以找到函数的地址,具体怎么修饰请看下一篇文章

5.引用

5.1 引用概念

引用不是新定义一个变量而是给已经存在的变量取了一个别名,编译器不会新开辟内存空间,而是和它引用的变量公用一个空间。
比如一个又瘦又高的人,你可以叫他“电线杆”。
又比如水浒传中的宋江被人们叫做“及时雨”。

int main()
{
	int a = 10;
	int& ra = a;
	cout << &a << endl;
	cout << &ra << endl;


	return 0;
}

在这里插入图片描述

5.2 引用特性

1、引用在定义时必须初始化
2、一个变量可以有多个引用
3、一个引用一旦有引用一个实体,再不能引用其他实体

#include <iostream>
using namespace std;
int main()
{
	int a = 10;
	//int& ra;引用不初始化,编译时会报错
	const int b = 10;
	//int &rb=b;权限扩大,编译报错,b是不可修改的
	const int& ra = b;
	double c =1.24;
	//int& rc = c;引用类型,不同编译报错

	return 0;
}

5.3 使用场景

做参数

#include <iostream>
using namespace std;
1.做参数
void Swap(int& a, int& b)
{
	int temp = a;
	a = b;
	b = temp;
}
int main()
{
	int a = 1, b = 2;
	Swap(a, b);

	return 0;
}

做返回值

#include <iostream>
using namespace std;
int& count()
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
	int& ret = count();
	cout << ret;
}

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

5.3传值和引用效率的比较

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

5.4引用和指针的区别

#include <iostream>
using namespace std;

int main()
{
	int a = 10;
	int& ra = a;
	ra = 20;
	int* sa = &a;
	*sa = 20;
	return 0;
	这两种方式都可以改变a的值,那他们有什么区别呢?
}

引用和指针的不同点

1.引用是一个变量的别名,而指针储存一个变量的地址。
2.引用在定义时必须初始化,指针没有要求(最好初始化不然就成了野指针)
3.一个引用一旦有引用一个实体,再不能引用其他实体,而指针可以在任何时候指向任何一个同类型的实体
4.没有NULL引用,但有NULL指针
5.sizeof含义不同,sizeof(引用)的大小是它引用对象的大小,而指针的大小是地址空间所占字节个数(32位平台下占4个字节)
6.引用自增就是引用的实体增加1,指针自增就是指针向后偏移一个类型的大小。

6.内联函数

6.1内联函数的概念

以inline修饰的函数叫做内联函数,编译时c++会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

#include <iostream>
using namespace std;
int Add(int a, int b)
{
	return a + b;
}
int main()
{
	int ret = 0;
	ret = Add(1, 2);
	return 0;
}

这是在反汇编下,函数的调用
在这里插入图片描述
如果在上述函数前增加inline关键字,将其改为内联函数编译时会用函数体替代函数的调用

#include <iostream>
using namespace std;
inline int Add(int a, int b)
{
	return a + b;
}
int main()
{
	int ret = 0;
	ret = Add(1, 2);
	return 0;
}

在这里插入图片描述
6.2 内联函数的特性

1.内联是一种时间换空间的做法,如果编译器将函数当作内联处理,会在编译阶段,用函数体替代函数调用。缺陷:可能会使目标文件变大,优势:少了开销,提高程序运行的效率。
2.inline对编译器只是一个建议,不同编译器inline实现的机制可能不同,一般建议:将函数规模小,不是递归、且频繁调用的函数用inline修饰。
3.inline不建议声明和定义分离,分离会导致链接错误

c++中有哪些技术可以替代宏?

1.常定义 换用const enum。
2.短小函数定义 换用内联函数。

7.auto关键字(C++11)

7.1 auto的运用背景

1.类型难于拼写
2.含义不明确导致容易出错

7.2 auto的运用规则

1.auto与指针和引用结合起来使用
用auto声明指针类型,用auto和auto*没有区别,但用auto声明引用时,要加&

#include <iostream>
using namespace std;
int main()
{
	int x = 10;
	auto a = &x;
	auto* b = &x;
	auto& c = x;
	*a = 20;
	cout << x << endl;;
	*b = 30;
	cout << x << endl;;
	c = 40;
	cout <<x << endl;
	return 0;
}

在这里插入图片描述

2.在一行定义多个变量

#include <iostream>
using namespace std;
int main()
{
	auto a = 1, b = 2;
	auto c = 3, d = 1.0;编译报错,因为c和d的初始化类型不同
	return 0;
}

7.3 auto不能推导场景

1.auto不能作为函数的参数
2.auto不能直接用来声明数组

此时编译器会报错,auto不能作为函数的参数
void Add(auto a)
{

}
#include <iostream>
using namespace std;
int main()
{
	int a[] = { 1,2,3 };
	auto b[] = { 1,2,3 };auto不能直接声明数组
	return 0;
}

8.基于范围的for循环(C++11)

8.1范围for使用条件与背景

1.c++11中引入了基于范围for循环,能够更方便的遍历数组,它是一块语法糖
2.迭代的范围必须是确定的
3.如果要改变数组要用(&)引用

#include <iostream>
#include "test.h"
using namespace std;
int main()
{
	int a[] = { 1,2,3 };
	for (auto x : a)
	{
		cout << x << " ";
	}
}

改变数值

#include <iostream>
#include "test.h"
using namespace std;
int main()
{
	int a[] = { 0,4,5 };
	for (auto &x : a)
	{
		x *= 2;
		cout << x << " ";
	}
}

9.指针空值nullptr(C++11)

在c++中NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)常量。因此在使用时可能会出现一些问题。因此在c++11中引入了nullptr,这样可以提高代码的健壮性。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值