【C++】auto关键字(c++11)

  • 概念

C++11中,auto不再是一个存储类型指示符,而是一个自动推导变量的类型,如:

#include <iostream>
#include <typeinfo>
using namespace std;

int TestAuto()
{
	return 10;
}

int main()
{
	int a = 10;
	auto b = a;//由a是int,可以推导出b的类型是int
	auto c = 'a';//由‘a’推导出c的类型是char
	auto d = TestAuto();
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;

    auto e;//这条语句编译不通过,使用auto定义变量时,必须对其进行初始化
	system("pause");
	return 0;
}
//typeid(b).name()是打印类型名称的函数

运行结果:

需要注意的是:

使用auto定义变量时,必须对其进行初始化,因为auto并非是一种类型的声明,而是一个类型声明时的“占位符”,编译器在编译期间会将auto替换为变量实际的类型。

  • auto使用规则

1.auto与指针和引用结合起来使用。用auto声明指针类型肘,用auto和auto*没有任何区別,但用auto声明引用类型吋必须加&

#include <iostream>
#include <typeinfo>
using namespace std;

int main()
{
	int x = 10;
	auto a = &x;
	auto* b = &x;
	auto& c = x;
	cout << typeid(a).name() << endl;
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	
	system("pause");
	return 0;
}

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

#include <iostream>
using namespace std;

void TestAuto()
{
	auto a = 1, b = 2;
	//auto c = 3, d = 4.0;//错误
	auto c = 3, d = 4;//正确
	cout << c << endl;
	cout << d << endl;
}

int main()
{
	TestAuto();
	
	system("pause");
	return 0;
}
  • auto不能自动推导的场景

1.auto不能作为函数的参数

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

2.auto不能用来直接声明数组

void TestAuto()
{
	int a[] = { 1, 2, 3 };
	auto b[3] = a;//auto类型不能出现在顶级数组类型中
}

3.为了避免与c++98中的auto发生混淆,c++11中只保留了auto作为类型推导的用法

4.auto最常见的就是会跟c++11中的新式for循环,还有lambda表达式进行配合使用

#include <iostream>
using namespace std;

int main()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (auto e : array)//依次取array里面的元素读给e
		cout << e << endl;
	
	system("pause");
	return 0;
}

运行结果:

5.auto不能定义类的非静态成员变量

6.实例化模板时不能使用auto作为模板参数

  • 基于范围的新式for循环(c++11)

在C++98中如果要遍历一个数组,可以按照以下方式进行:

void TestFor()
{
intarray[]={1,2,3,4,5};
for (int i = 8; i < sizeof(array) / sizeof(array[0]); ++i )
   array[i] *= 2;

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

}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号”:”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

int main()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (auto e : array)//依次取array里面的元素读给e
		cout << e << " ";
	
	system("pause");
	return 0;
}

如果此时想要打印array数组元素的2倍时,就必须加引用&:

#include <iostream>
using namespace std;

int main()
{
    int array[] = { 1, 2, 3, 4, 5 };
    for(auto& e : array)//遍历数组,给数组的每个对象*2;
        e = e * 2;

    for (auto& e : array)//遍历数组,依次取出数组里面的元素,赋给e
        cout << e << " ";
    system("pause");
    return 0;
}

分析:不加“&”的意思是取出array里面的每个对象,赋给e,e虽然被改变了,但数组里面的对象并没有变;加“&”表示e是数组里面 每个对象的别名,此时e一改变,数组里面的每个对象也会改变,因为e是每个对象的别名。

注意:与普通循环类似,可以用continue来结束本次循环, 也可以用break来跳出整个循环。

 

  • for的使用条件

1. for循环迭代的范围必须是确定的,对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围,以下代码就有问题:

void Test(int array[])
{
	for (auto& e : array)
		cout << e <<endl;
}

分析:这个代码编译不通过,此时的array不再是数组而是一个指针,for的范围不确定。

2.for循环要支持迭代器,还得支持++和==。

  • nullptr(c++11)

在C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下方式对其进行初始化:

void TestPtr(){

int* p1 = NULL;int* p2 = 0;

而NULL实际是一个宏, 在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef_ .cplusplus
#define NULL  0
#else
#define NULL ((void *)0)
#endif
#endif

我们发现NULL在c++中被定义为整形常量0,在c语言中被定义为无类型指针(void* )的常量。这种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

#include <iostream>
using namespace std;


void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
int main()
{
	f(0);//调f(int)
	f(NULL);//调f(int)
	f((int*)NULL);//调f(int*)
	system("pause");
	return 0;
}

运行结果:

这个程序的本意是:想通过f(NULL)调用fint*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。在C++98中,字面常量0既可以是一个整形数字, 也可以是无类型的指针(Void)常量, 但是编译器默认情况下将其看成是一个整形常量, 如果要将其按照指针方式来使用,必须对其进行强转(void *)0。

  • nullptr

为了考虑兼容性,C++11并没有消除常量0的二义性,而是给出了全新的nullptr,表示空值指针。C++11为什么不在NULL的基础上进行扩展,这是因为NULL以前就是一个宏, 而且不同的编译器厂商对于NULL的实现可能不太相同,而且直接扩展NULL,可能会影响以前旧的程序。因此:为了避免混淆,C++11提供了nullptr,即: nullptr代表- 个指针空值常量。nullptr是有类型的, 其类型为nullptr. _t,仅仅可以被隐式转化为指针类型,nullptr. _t被定义在头文件中:

typedef decltype(nullptr) nullptr_ t;

需要注意的是:

1.在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。

2.在C++11中,sizeof(nullptr) 与sizeof(void*)0)所占的字节数相同。

3.为了提高代码的健壮性,建议在后续表示指针空值时,最好使用nullptr。

这里还有常见的一类题:

请区分:NULL、0、'\0'、"\0"?

NULL:是被定义出来的一个宏,它不是关键字,值为0;

0:是整形的0,值为0;

'\0':是字符0,值为0;

"\0":是字符串;

计算:

#include <iostream>
using namespace std;
int main()
{
    char str[] = "\0";
    cout << strlen(str)<< endl;//0字节
    cout << sizeof(str) << endl;//2个字节
    system("pause");
    return 0;
}

其中strlen(str)大小为0,因为转义字符\+0,就是字符串中的结束标志"\0",只要遇到"\0",它就自动停下来了,所以strlen(str)大小为0;sizeof(str)大小为2个字节,转义字符\+0是一个字符,还有字符串结束标志的那个"\0",加起来就是2个字节。

再比如:

#include <iostream>
using namespace std;

int main()
{
    char str[] = "\\0";
    cout << strlen(str)<< endl;//2个字节
    cout << sizeof(str) << endl;//3个字节
    system("pause");
    return 0;
}

这个程序里面strlen(str)大小为2个字节,转义字符\+\转义为\,后面还有个数字0,总共是2个字节;sizeof(str)大小为3个字节。

猜你喜欢

转载自blog.csdn.net/qq_42270373/article/details/83963784
今日推荐