C++入门(保姆级教程)

这篇具有很好参考价值的文章主要介绍了C++入门(保姆级教程)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、C++关键字

二、命名空间

2.1 C语言中的命名冲突 

2.2 C++中命名空间

2.2.1 命名空间的定义

2.2.2 命名空间的特性

2.2.3 命名空间的使用

2.2.4 补充知识

2.2.4 C++库的命名空间

三、C++中的输入&输出

四、缺省参数

4.1  定义

4.2 缺省参数的分类

4.2.1 全缺省参数

4.2.2 半缺省参数

4.3 示例:

五、函数重载

5.1 定义

5.2 函数重载示例

5.2.1 参数个数不同

5.2.1 参数类型不同

5.2.1 类型顺序不同

5.3 为什么C++支持函数重载

六、引用

6.1 定义

6.2 引用特性

6.2.1 引用在定义时必须初始化

6.2.2 一个变量可以有多个引用

6.2.3 引用一旦引用了一个实体,再不能引用其他实体

6.3 引用做参数(输出型参数)

6.3.1 示例

6.3.2 效率比较

6.4 引用做返回值

6.4.1 引用做返回值的优势

6.4.2 性能比较  

6.4.3 引用缺点

6.5 常引用

6.6 引用和指针

七、auto关键字

7.1 概念

7.2 auto的使用事项

7.2.1 auto与指针和引用结合起来使用

7.2.2 在同一行定义多个变量

7.3 auto不能推导的场景

7.3.1 auto不能作为函数的参数

7.3.2 auto不能直接用来声明数组

八、基于范围的for循环

8.1 概念

8.2 使用条件

九、内联函数

9.1 概念

9.2 适用情况

9.3 注意问题

十、指针空值nullptr(C++)


   C++是在C语言的基础上,容纳进去了面向对象的编程思想,并且增加了许多有用的库,以及编程范式等,所以C++兼容C,也就是我们写C语言的代码在C++编译环境下也依然能够编译通过。

注意:C++兼容C语言,本篇文章在前半部分主要还是用C语言的书写习惯来讲解C++中的命名空间,所以在前半部分使用的都还是#include<stdio.h>。

一、C++关键字

C++关键字一共有63个。

   在这里暂时不进行逐一解释,在后期博客会对此进行分析,大家可以先去菜鸟教程中进行了解,链接如下:C++ 的关键字(保留字)完整介绍 | 菜鸟教程 (runoob.com)。

二、命名空间

   在一方面来讲C++是在C的基础上的完善,所以C++要去解决C语言中出现的一些问题,首先就是命名冲突的问题。

2.1 C语言中的命名冲突 

   我们来观察下面的两个代码:

代码一:

#include<stdio.h>

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

c++教程,c++,开发语言,c语言

代码二:

#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
	printf("%d\n", rand);
	return 0;
}

c++教程,c++,开发语言,c语言

     对于上述的两个代码,代码一可以正常运行,但是代码二无法正常运行,这是为什么呢?

c++教程,c++,开发语言,c语言

    在上述图片中,我们知道代码二运行不通过的原因是由于rand重定义,我们包含了库中的头文件,即 #include<stdlib.h> ,上述头文件中定义了一个函数rand,包含头文件相当于把头文件中的内容在预编译期间拷贝一份过来,相当于在全局域中,在代码二中我们也定义了一个全局变量rand,也在全局域中,这时就会有命名冲突的问题

2.2 C++中命名空间

    命名冲突有两种:

  1. 和库冲突。
  2. 和项目组中的其他人冲突。   

   我们知道不同的域中可以有同名的变量,C++解决了C语言中命名冲突的问题,C++使用namespace-命名空间(关键字)来解决命名冲突的问题,使用namespace定义一个域,用域进行隔离。

2.2.1 命名空间的定义

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

   例如上述的代码二,我们就可以定义一个名字是A的命名空间,rand就在A这个命名空间域了,将rand变量和stdlib.h中的rand函数进行区分。

#include<stdio.h>
#include<stdlib.h>

namespace A
{
	int rand = 0;
}

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

   在上述代码中,相当于将全局变量rand定义到了一个名字是A的域中,而#include<stdlib.h>是将stdlib.h中的内容拷贝到当前文件中,其中的rand函数在全局域中,两个rand命名的函数和变量不是处于同一个域,就解决了命名冲突的问题。

2.2.2 命名空间的特性

1.命名空间中可以定义变量/函数/类型。

namespace A
{
	int rand = 0;
	int Add(int x, int y)
	{
		return x + y;
	}

	struct A
	{
		int a[5];
		char c;
	};
}

2.命名空间可以嵌套。

   当一个命名空间足够大的时候,命名空间内部的变量或者函数也会有命名冲突的问题,这时候就需要命名空间的嵌套了。

namespace A
{
	int rand = 0;
	int Add(int x, int y)
	{
		return x + y;
	}

	struct A
	{
		int a[5];
		char c;
	};
	namespace B
	{
		int a = 0;
		char c = 'k';
	}
}

3.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。

例如test.h和hll.cpp中都有A这个命名空间,在最后编译运行时,会合成到同一个命名空间中去。

一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。

2.2.3 命名空间的使用

#include<stdio.h>

namespace A
{
	int a = 3;
}

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

   对于上述的代码,编译会不通过,在main函数中有要去打印变量a,但在搜索时并没有找到变量a 的定义,这是由于在对变量a进行搜索时,我们不会主动地去命名空间域中去搜索

   对于命名空间域中的成员,我们不能直接使用,什么时候才去命名空间域搜索 ?

   命名空间中成员该怎么使用呢?

1.指定访问命名空间域。

     在这里我们使用 ::(域作用限定符), ::加在变量的前面,表示去::左边的域访问。注意:如果左边的域是空白,就代表是全局域。

#include<stdio.h>

namespace A
{
	int a = 3;
}

int a = 5;

int main()
{
	printf("%d\n", ::a); //::左边是空白,代表去全局域访问
	printf("%d\n", A::a);   //::左边的域是A,代表去A这个命名空间域访问
	return 0;
}

2.将命名空间全部展开。(使用using namespace 命名空间名称 引入)

#include<stdio.h>

namespace A
{
	int a = 3;
}

using namespace A;

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

     使用using namespace A;将命名空间域A展开,但是展开就相当于将A中的内容放在全局中,我们使用命名空间的初衷是为了防止和别人或者和库中的内容有冲突,将自己定义的变量等使用作用域限定起来,使用using namespace A;将其展开,可能又会造成命名冲突的问题,所以我们不推荐使用这个方式,但是在我们平时写代码的过程中,命名冲突可能性小,所以使用这个方式。

3.把命名空间中常用的部分展开。

    C++的标准库是使用的std这个命名空间,我们想要使用cout(输出)和endl(换行),可以单独将他们展开。

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


int main()
{
	cout << "hello" << endl;
}

2.2.4 补充知识

   当一个文件中有三个同名的变量,分别在局部域,全局域以及命名空间域,那么他们的访问顺序是怎样的?

#include<stdio.h>
#include<stdlib.h>

int a = 0;  //全局域

namespace A
{
	int a = 3;
}

int main()
{
	int a = 1;  //局部域
	printf("%d\n", a);

	return 0;
}

     对于不同的域中的三个同名的变量来说,优先去访问局部变量,然后是全局变量,最后如果展开了命名空间域或者指定访问才会去命名空间域。

2.2.4 C++库的命名空间

   C++标准库中的函数或者对象都是在命名空间std中定义的,所以我们要使用标准库中的函数或者对象都要用std来限定。

   我们会发现在写C++时,我们在包含头文件时不再加.h了,这是因为C++有了命名空间这个定义之后,就把C++标准库中的函数或者对象都用std这个命名空间包起来了,为了和旧的库进行区分,就定义了新的标准,不再使用.h了。

三、C++中的输入&输出

   在这里由于没有类和对象的知识,所以简单的了解一下即可,之后会进行讲解。

   cout相当于输出函数,cin相当于输入函数,endl相当于换行,注意cout和cin都可以连续一行插入或输出多个变量,会自动识别类型。

#include<iostream>  //C++中标准库,输入输出是由iostream库提供的
using std::cout;
using std::endl;
using std::cin;

int main()
{
	int a = 0;
	int x = 0;
	double d = 0;
	cout << "hello" << " " << 'd' << ' ' << 's' << a << endl;  //endl相当于换行
	cin >> x >> d;
	cout << "hello" << " "<< x << " " << d << endl;

	return 0;
}

四、缺省参数

    C++前期是在解决C语言中出现的问题,所以我们又引出了缺省参数这一概念。

4.1  定义

   缺省参数声明函数的时候可以让 最右边的连续若干个 参数有缺省值,在调用函数的时候,如果不写相应位置的参数,则调用的参数就为缺省值。

例如:

#include<iostream>  //C++中标准库,输入输出是由iostream库提供的
using std::cout;
using std::endl;
using std::cin;

void Func(int a = 0)  //在形参位置上,给一个缺省值
{
	cout << a << endl;
}

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

4.2 缺省参数的分类

4.2.1 全缺省参数

   全缺省参数,即在声明时,给每一个形参一个缺省值。

#include<iostream>  //C++中标准库,输入输出是由iostream库提供的
using std::cout;
using std::endl;
using std::cin;

void Func(int a = 0, int b = 5,int c = 8)  
{
	cout << "a =" << " " << a << endl;
	cout << "b =" << " " << b << endl;
	cout << "c =" << " " << c << endl;
}

int main()
{
	Func();
	Func(5);//将5传给a
	Func(5,10);  //将5传给a,将10传给b
	Func(5,10,6);  //将5传给a,将10传给b, 将6传给c
	return 0;
}

   注意在这里传参的时候,只能从左往右依次传参,不能跳跃传参。

//即不能如下:
Func(5, ,10);

4.2.2 半缺省参数

   半缺省,在声明函数时,给部分参数缺省值,但是这部分也有要求。

  1. 半缺省参数必须从右往左来给出,不能间隔着给。(如果从左往右来给出,那么在函数传参时就无法分辨是给哪一个参数传的值)
#include<iostream>  //C++中标准库,输入输出是由iostream库提供的
using std::cout;
using std::endl;
using std::cin;

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

int main()
{
	Func(5);//将5传给a
	Func(5, 10);  //将5传给a,将10传给b
	Func(5, 10, 6);  //将5传给a,将10传给b, 将6传给c
	return 0;
}

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

例如我们在test.h文件中提供Func函数的声明,在Test.cpp文件中提供Func函数的定义:

c++教程,c++,开发语言,c语言

c++教程,c++,开发语言,c语言

    在上述两个文件中,我们在声明/定义中都出现了缺省参数,此时运行不通过。

c++教程,c++,开发语言,c语言

     为什么不允许声明和定义中都给缺省值?为了避免如果在声明和定义中给的缺省值不一致,那么编译器按照哪一个来执行的问题。

     那么是声明给or定义给呢?
     当然是声明给。

如果定义给的话会出现以下的问题:
 

c++教程,c++,开发语言,c语言

c++教程,c++,开发语言,c语言 c++教程,c++,开发语言,c语言 

      如果定义给,声明不给,那么在编译期间就会出错。

4.3 示例:

在这里我们使用之前写过的栈的初始化来表示:

c++教程,c++,开发语言,c语言

c++教程,c++,开发语言,c语言

c++教程,c++,开发语言,c语言

   对于上述栈的初始化,如果开辟空间小的话,要进行扩容,但是扩容会有一定的消耗,但是如果开辟空间大的话,就会造成空间的浪费,我们可以使用缺省参数,当已经知道需要开辟的空间大小时指定capacity的大小,未知时,就使用缺省值

五、函数重载

5.1 定义

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

   对于这样的构成函数重载的两个函数,在进行函数调用时,编译器会自动识别实参的类型来确定调用哪一个函数。

   注意:两个同名函数只有返回类型不同,不构成函数重载。

5.2 函数重载示例

5.2.1 参数个数不同

#include<iostream>  //C++中标准库,输入输出是由iostream库提供的
#include"test.h"
using std::cout;
using std::endl;
using std::cin;

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

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

int main()
{
	f();
	f(5);

	return 0;
}

   上述两个函数的参数个数不同,构成函数重载。

5.2.1 参数类型不同

#include<iostream>  //C++中标准库,输入输出是由iostream库提供的
#include"test.h"
using std::cout;
using std::endl;
using std::cin;

int add(int x, int y)
{
	cout << "int add(int x,int y)" << endl;
	return x + y;
}

double add(double x, double y)
{
	cout << "int add(double x,double y)" << endl;
	return x + y;
}

int main()
{
	cout << add(1, 2) << endl;
	cout << add(1.2, 2.3) << endl;

	return 0;
}

   上述的两个函数函数名相同,他们的函数形参的类型不同,构成函数重载。

5.2.1 类型顺序不同

#include<iostream>  //C++中标准库,输入输出是由iostream库提供的
#include"test.h"
using std::cout;
using std::endl;
using std::cin;

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

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

int main()
{

	f(5,'g');
	f('g', 5);

	return 0;
}

   上述两个函数的形参参数类型顺序不同,构成函数重载。

5.3 为什么C++支持函数重载

   我们使用下面的例子来具体探讨:

c++教程,c++,开发语言,c语言

c++教程,c++,开发语言,c语言

c++教程,c++,开发语言,c语言

   要探索C++为什么支持函数重载,我们要从编译链接过程来看。

c++教程,c++,开发语言,c语言

c++教程,c++,开发语言,c语言

      在c语言中,生成的符号表中记录的只有函数的名字以及地址,即类似于下方(下方只是粗大致画的,实际中并不是这样):

c++教程,c++,开发语言,c语言

      而在C++的符号表记录中,会记录形参的类型,所以它支持函数重载。

六、引用

   在c语言中,在学习指针的时候是一大难点,C++中退推出了引用来更加方便的解决了一部分与指针相关的问题。

6.1 定义

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

类型& 引用变量名(对象名) = 引用实体;

注意:引用类型必须和引用实体是同一类型的。

   下面就是一个引用的例子:

int main()
{
	int a = 0;
	int& b = a;  //b是a的别名,b和a使用的同一块空间
	int& c = b;  //c是b的别名,b是a的别名,即c是a的别名,c,b和a使用的同一块空间

	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;

	return 0;
}

c++教程,c++,开发语言,c语言

6.2 引用特性

6.2.1 引用在定义时必须初始化

int a = 0;
int& b = a;  //b是a的别名,b和a使用的同一块空间
int& c = b;  //正确
int& d;  //是错误的,必须要初始化

6.2.2 一个变量可以有多个引用

#include<iostream>
using namespace std;

int main()
{
	int a = 0;
	int& b = a;
	int& c = a;
}

6.2.3 引用一旦引用了一个实体,再不能引用其他实体

#include<iostream>
using namespace std;

int main()
{
	int a = 0;
	int& b = a;
	int& c = a;
	
	//引用一旦引用了一个实体,再不能引用其他实体
	int x = 10;
	c = x; //在这里是将x的值赋给c,c依旧是a/b的别名

	return 0;
}

引用的使用场景

6.3 引用做参数(输出型参数)

6.3.1 示例

#include<iostream>
using namespace std;

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

int main()
{
	int a = 10;
	int b = 5;
	Swap(a, b);
	return 0;
}

   之前我们用函数实现交换两个数的值,要用指针,在这里我们就可以使用引用了,x相当于a的别名,y相当于b的别名,改变x即改变a。

6.3.2 效率比较

   我们使用下面的函数来测试引用与非引用的效率。

#include<iostream>
using namespace std;
#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a){}

void TestFunc2(A& a){}

void TestRefAndValue()
{
	A a;
	// 以值作为函数参数
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc1(a);
	size_t end1 = clock();
	// 以引用作为函数参数
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc2(a);
	size_t end2 = clock();
	// 分别计算两个函数运行结束后的时间
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

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

c++教程,c++,开发语言,c语言

   我们可以看出使用引用 ,效率明显提高。

6.4 引用做返回值

   下面我们会通过几个代码示例来具体体会引用做返回值的优势与弊端。

6.4.1 引用做返回值的优势

   在下面,我们会通过一段代码的传值返回和传引用返回来比较用引用做返回值的优势。

   在下面的两段代码中我们使用传值返回:

1. n是局部变量

int count()
{
	int n = 0;
	n++;
	return n;
}

int main()
{
	int ret = count();
	return 0;
}

c++教程,c++,开发语言,c语言

2.n是静态变量

int count()
{
	static int n = 0;
	n++;
	return n;
}

int main()
{
	int ret = count();
	return 0;
}

c++教程,c++,开发语言,c语言

     我们会发现在上面的传值返回中,不论函数中的变量是局部变量还是静态变量,都需要有一个临时变量协助完成返回,如果我们不想生成临时变量怎么办?用引用返回。

c++教程,c++,开发语言,c语言

6.4.2 性能比较  

值和引用作为函数的返回值的性能比较:

#include<iostream>
using namespace std;
#include<time.h>
struct A { int a[1000]; };

A a;
//值返回
A TestFunc1() { return a; }
//引用返回
A& TestFunc2() { return a; }

void TestReturnByRefOrValue()
{
	//以值返回作为函数的返回值类型
	size_t begin1 = clock();
	for (size_t i = 0; i < 100000; i++)
	{
		TestFunc1();
	}
	size_t end1 = clock();
	//以引用作为函数的返回值类型
	size_t begin2 = clock();
	for (size_t i = 0; i < 100000; i++)
	{
		TestFunc2();
	}
	size_t end2 = clock();
	//计算两个函数运算完成之后的时间
	cout << "TestFunc1 time:" << end1 - begin1 << endl;
	cout << "TestFunc2 time:" << end2 - begin2 << endl;

}

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

c++教程,c++,开发语言,c语言

6.4.3 引用缺点

   在一些时候,我们无法用引用作为返回值,它会导致一些错误。

错误示例:
 

int& count()    //返回的是n的别名
{
	int n = 0;
	n++;
	return n;
}

int main()
{
	int ret = count();
	return 0;
}

   在上述的情况下使用引用作为函数的返回类型,就会出问题,在上述代码中出现了野指针的访问。

c++教程,c++,开发语言,c语言

   在上面的图中,我们可以明显的看到当main函数调用count函数时,n创建,当调用结束,栈帧销毁,n是在count函数中的局部变量,n的空间还给操作系统

   在这里ret的值是不确定的,count函数返回的是n的别名,当count函数调用结束,将n的别名对应空间的值(即n的值)拷贝给ret,如果count函数调用结束,栈帧销毁,没有清理栈帧,那么ret的结果侥幸是正确的,如果count函数调用结束,栈帧销毁,清理栈帧,那么ret的结果是随机值

总结:
1.基本任何场景都可以使用引用传参

2.谨慎使用引用做返回值,出了函数作用域,变量就不在了,就不能使用引用返回,如果出了函数作用域,变量还在,就可以使用引用做返回类型

6.5 常引用

   常引用是指利用 const 修饰的引用类型。 由于引用本身已经绑定不可解绑,因此所用的 const 引用都是底层 const,即引用对象不能改变 (俗称常引用)。

在引用的过程中,权限不能放大,但是引用过程中,权限可以平移或者缩小。

下面通过几个例子来看常引用。

    int a = 0;
	int& b = a;     //正确,b是a的别名


	const int a = 0;
	int& b = a;    //错误,a是const修饰的,不能改变,而b是int类型的引用,引用不能放大权限

	const int c = 0;
	int d = c;      //正确,把c的值拷贝给d,没有放大权限
    int x = 0;
	int& y = x;   //正确,y是x的别名
	const int& z = x;   //正确,引用能够缩小权限

	int x = 0;
	int& y = x;
	const int& z = x;  //当z这个别名时,x的值不能改变
	++x;      //当是x这个名字时,x的值可以改变
const int& m = 10;   //m是常量10的别名,权限的平移
//当类型不同时,会发生隐式类型转换,在转换时,中间会产生临时变量,产生的临时变量具有常性,

	double dd = 1.11;
	int ii = dd;       //当类型不同时,会发生隐式类型转换
	int& isi = dd;        //错误

	double dd = 1.11;
	int ii = dd;
	const int& rii = dd;  //正确

c++教程,c++,开发语言,c语言

int func1()
{
	static int x = 0;
	return x;
}

int main()
{
	//int& ret = func1();   //错误,函数返回时也会产生一个临时变量,临时变量具有常性,此处是对权限的扩大
	const int& ret = func1();  //正确,权限的平移
	return 0;
}

6.6 引用和指针

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

七、auto关键字

   随着程序越来越复杂,程序中用到的类型也越来越复杂,可能出现类型难于拼写等问题,这时C++就提出了auto关键字。

7.1 概念

    C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一
个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得
int main()
{
	int a = 0;
	int b = a;
	auto c = b;   //根据右边的表达式自动推导c的类型
	auto d = 1 + 1.11;   //根据右边的表达式自动推导d的类型
    
	//typeid可以打印类型
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;
	return 0;
}

c++教程,c++,开发语言,c语言

   注意:

   使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto 的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编 译期会将auto替换为变量实际的类型

7.2 auto的使用事项

7.2.1 auto与指针和引用结合起来使用

   用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须
加&。
int main()
{
	int x = 10;
	auto a = &x;    //推导出来a是指针
	auto* b = a;    //指定必须是指针
	auto& c = x;    //指定是引用
	return 0;
}

7.2.2 在同一行定义多个变量

   当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器就会报错,因为编译器实际上只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

auto a = 10, b = 2;
//auto ac = 0, d=1.11;//错误

7.3 auto不能推导的场景

7.3.1 auto不能作为函数的参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

7.3.2 auto不能直接用来声明数组

void TestAuto()
{
	int a[] = { 0,1,2 };
	//auto a[] = { 4,3,5 };    //错误

}

八、基于范围的for循环

8.1 概念

    对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因
此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范
围内用于迭代的变量,第二部分则表示被迭代的范围
int main()
{
	int arr[] = { 1,2,3,4,5 };
	//c语言中访问数组
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
		arr[i] *= 2;

	for(int *p=arr; p<arr+ sizeof(arr) / sizeof(arr[0]);p++)
		cout<<*p<<endl;

	//范围for
	//依次取数组中数据赋值给e
	//自动迭代,自动判断结束
	for (auto e : arr)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

如果我们要使用范围for来修改数组中的数据:

int main()
{
	//修改数据

	//错误,取arr中数据依次赋值给e,相当于依次取arr[0]、arr[1]......拷贝给e,e的改变不会影响数组的内容
	for (auto e : arr)
	{
		e *= 2;
	}

	//正确,e开始是arr[0]别名,然后是arr[1]别名,e的修改会影响数组
	for (auto& e : arr)
	{
		e *= 2;
	}

	return 0;
}

   注意上述的范围for中,auto,e都可以改变,arr是数组。

8.2 使用条件

for循环迭代的范围必须是确定的。

int main()
{
	int arr[] = { 0,1,2,3,4,5 };
	int* p = arr;

	//错误,因为for的范围不确定
	for (auto& e : p)
	{
		e *= 2;
	}
	return 0;
}

九、内联函数

9.1 概念

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

9.2 适用情况

   内联函数适用于短小的频繁调用的函数,inline对于编译器仅仅只是一个建议,最终是否成为inline,编译器自己决定。

   内联函数不适用于:1. 比较长的函数     2. 递归函数

inline int Add(int x, int y)
{
	return (x + y) * 10;
}
int main()
{
	for (int i = 0; i < 100; i++)
	{
		cout << Add(i, i + 1) << endl;
	}
	return 0;
}

9.3 注意问题

   inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

十、指针空值nullptr(C++)

void Testptr()
{
	int* p1 = NULL;
}
NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量
void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
int main()
{
	f(0);
	f(NULL);
	f((int*)NULL);
	return 0;
}

   在上述代码中,我们想要调用void f(int*),但是发现每次调用的都是void f(int),在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void*)0。文章来源地址https://www.toymoban.com/news/detail-731284.html

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

到了这里,关于C++入门(保姆级教程)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Shopify开发入门-前端保姆级教程

    本文旨在介绍Shopify开发入门、环境、配置等,帮助开发者配置环境、了解各个开发模式的区别及用途;已有Shopify开发经验者可退出,以免浪费你的宝贵时间。 本文5k字+,图片、链接、代码块较多,请耐心阅读~ 最近在调研Shopify开发,对其也有了一定的认识、了解;即将这些

    2024年02月16日
    浏览(41)
  • 保姆级教程——VSCode如何在Mac上配置C++的运行环境

    点击官网链接,下载对应的pkg,安装打开; 点击箭头所指插件商店按钮,yyds; 下载C/C++ 插件; ![外链图片转存 ! 如果安装失败,可手动安装; 打开Github:https://github.com/vadimcn/vscode-lldb/releases; 如果是基于Intel的Mac选择codelldb-×86_64-darwin.vsix, 如果是基于Apple Silicon的Mac选择

    2024年02月09日
    浏览(82)
  • Spring注解开发 -- Spring快速入门保姆级教程(二)

    为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。 (博客的参考源码可以在我主页的资源里找到,如果在学习的

    2024年02月09日
    浏览(47)
  • 万字长文 | 保姆级的后台服务器开发C++学习路线

      这一篇的主题是「Linux C/C++ 服务器/后台开发学习路线」。     这样的文章相信大家都见得不少了,写之前也非常忐忑,能不能和其它人写得不一样, 也定下了一个目标,这篇文章,不能是简单的堆砌学习资源和书单推荐,更要细化如何有效的去执行落地。     争取

    2024年02月06日
    浏览(41)
  • C语言基础入门——配置C/C++环境及多种运行方式(保姆级教程)

    本文章主要讲解新手在运行C 程序的源文件.c中的一些简单操作。 其主要的编辑器有:VSCode、CodeBlocks、VC++ 6.0、CodeLite、Notepad、eclipse、 dev-C++、 C-Free,vim/vi(Linux/UNIX 操作系统)等。 其主要的编译器有:Gcc、Clang(苹果公司开发的C语言编译器前端)、MSVC、Turbo C等。 文章中所

    2024年04月15日
    浏览(76)
  • 【Go语言】Golang保姆级入门教程 Go初学者chapter2

    setting的首选项 一个程序就是一个世界 变量是程序的基本组成单位 变量的使用步骤 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zuxG8imp-1691479164956)(https://cdn.staticaly.com/gh/hudiework/img@main/image-20230726152905139.png)] 变量表示内存中的一个存储区 注意:

    2024年02月14日
    浏览(129)
  • 【Go语言】Golang保姆级入门教程 Go初学者chapter3

    下划线“_”本身在Go中一个特殊的标识符,成为空标识符。可以代表任何其他的标识符,但是他对应的值就会被忽略 仅仅被作为站维度使用, 不能作为标识符使用 因为Go语言中没有private public 所以标记变量首字母大写代表其他包可以使用 小写就是不可使用的 注意:Go语言中

    2024年02月13日
    浏览(62)
  • yolov8实战第六天——yolov8 TensorRT C++ 部署——(踩坑,平坑,保姆教程)

    C++ 结合 TensorRT 部署深度学习模型有几个关键优势,这些优势在各种工业和商业应用中极其重要: 高效的性能 :TensorRT 通过优化深度学习模型来提高推理速度,减少延迟。这对于实时处理应用(如视频分析、机器人导航等)至关重要。 降低资源消耗 :TensorRT 优化了模型以在

    2024年04月13日
    浏览(42)
  • 【Go语言】Golang保姆级入门教程 Go初学者介绍chapter1

    Golang的学习方向 区块链研发工程师: 去中心化 虚拟货币 金融 Go服务器端、游戏软件工程师 : C C++ 处理日志 数据打包 文件系统 数据处理 很厉害 处理大并发 Golang分布式、云计算软件工程师:盛大云 cdn 京东 消息推送 分布式文件系统 2、Golang的应用领域 区块链应用:区块链

    2024年02月15日
    浏览(70)
  • 从C语言到C++:C++入门知识(1)

    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关C++语言的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、   目录 前言: 1. 什么

    2024年02月07日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包