C++中数据处理类型(类型别名,auto, decltype类型指示符)

发布于:2022-12-22 ⋅ 阅读:(571) ⋅ 点赞:(0)


前言:随着程序的越来越复杂,程序中用到的类型也越来越复杂,这些主要体现在两方面:第一个是遇到一些类型时,它们的名字既难写又难记,还无法确定其含义;第二个是有时候根本搞不清楚需要什么类型,所以程序员不得不回头去上下文寻找,这时候就需要类型别名来方便我们使用。

一、 类型别名

类型别名 是一个名字,它是某种类型的同义词,通俗的说就是另一个名字。适用类型别名有很多好处,它让复杂的类型名字变得简单明了、便于理解和使用,还有助于程序员清楚地知道该类型的真实目的,反正就是让你更加好理解,把复杂的类型简单化,老铁们非常的好用,给一个大大的赞。

1.typedef

C++有两种方法定义别名,第一种就是关键字typedef,也是比较传统的定义
例如:

typedef long int l_i;
l_i num;//等价于long int num;
typedef const char * cc_;

看上面这两行代码:
第一行我们将 long int 这个数据类型重新定义成了 l_i, 看看这个用法,啧,哎呦呦,这也太妙了吧,以后只要需要用到long int 定义的变量就可以用l_i 这个名字来代替,这简直不要太爽好吧。

第二个也是一样的,如果你想定义多个 const char * 类型的指针变量,又闲它比较长,就可以重命名一下,使它变得简单好记,但这里建议你重命名和原来名字有一些联系,这样更容易记住。const char *cc_ 比较,用单词的第一个字符做重命名,* 用 _ 来代替。

typedef还有很多用途,这里只指出了常用的用法,其他更多的用法需要你们以后慢慢探寻。

2.using

别名声明using 是C++11新标准规定的新的方法,这个用法也比较好用,使用也方便,上面的和这个看大家喜好,喜欢什么用什么。让我们看一下用法:

using SI = Sales_item;//
SI item;//等价于Sales_item;

这种声明别名的方式偏向于等式类型的,可能会有一些小伙伴喜欢,不过哪种方式不影响你的程序。

3.指针、常量和类型别名

如果某个类型别名指代的是复合类型或者常量的话,那么将它放在程序里面声明语句的话可能会造成一些错误和意想不到的后果。例如下面的语句用到了类型 pstr , 它实际上是类型 char* 的别名:

typedef char * pstr;
const pstr ct = 0;
//ct是指向 char的常量指针
const pstr *ps;//ps是一个指针
//它指向的对象是一个指向char的常量指针

上述两条语句的基本类型都是const pstr类型,const 是对给定类型的修饰,也就是对pstr 的修饰。pstr实际上是指向char 的指针, 因此,const pstr 就是指向char 的常量指针,而非指向常量字符(const char)的指针。

遇到类型别名声明语句时,人们往往会错误的类型别名替代成它们原来的样子来理解语句,例如:

const pstr ct  = 0;
cosnt char * ct = 0;
//这是对const pstr ct 的错误理解

在强调一遍,这种理解是错误的。 声明语句用到pstr时,其基本数据类型是指针。可是用 char* 重写声明时,数据类型就变成了char, * 成为了声明符的一部分。这样改写的结果是, const char 成为基本数据类型。前后两种声明的含义截然不同,前者声明了一个指向char 的常量指针,后者则是声明了一个指向const char 的指针。

二、auto类型说明符

编程时常常需要将表达式的值赋值给一个变量,但有时候又不知道这个表达式返回的值是什么类型,所以这个变量就不知道是什么类型。为解决这个问题,C++11新标准引入了 auto 这个类型说明符,用了它就能让编译器代替我们去分析表达式所返回的值的类型。auto 是让编译器通过初始值来推断变量的类型,所以,auto 的定义必须有初始值,例如:

//由 val1 和 val2 相加的结果
//编译器就可以推断出item的类型
auto  item  =  val1  +  val2;
//item 初始化为两个相加的结果
auto  ite;//这是很严重的错误
//auto定义必须初始化

如果两个变量的类型是一个类,那item 的类型就是一个类;如果两个变量是double 类型,那么item的类型就是一个double

使用auto 也能在一条语句中定义多个变量,因为一条声明语句中只能有一个基本数据类型,所以该声明语句中所有变量的初始基本数据类型都必须一样。例如:

auto i = 1, *p = &i;
//正确,i是整型,p是整型指针
//两个的基本数据类型都是整形

auto  sz = 1, pi = 3.14;
//错误,sz 和 pi的基本数据类型不一样

复合类型、常量和auto

编译器推断出来的auto类型有时候和初始值类型并不完全一样,这时候编译器会适当地改变结果类型使其更符合初始化规则。
比如我们使用引用其实是使用引用的对象,当引用被用作初始值时,真正参与初始化的其实是引用所指向的对象的值,此时编译器已引用对象的类型作为auto 的类型。听起来可能会有一点抽象,下面有代码得大家解释一下:

int i = 1;
int &r = i;
auto a = r;
// r是i的引用,r是和i是连接的
//改变r相当于改变i的值。
//而r作为引用赋值给a,
//所以auto将直接分析i的类型作为a的类型
//所以a的类型是整形

其次,auto一般会忽略掉顶层const(至于什么是顶层const和底层const,后面会出),同时底层const会被保存下来,比如当初始指是一个指向常量的指针是:

const int ci = i, &cr = ci;
auto b = ci;
//b是一个整数(ci的顶层const特性被忽略掉了)
auto c = cr;
//c是一个整数(cr是ci的别名,ci的顶层const特性又被忽略掉了)
auto d = &i;
//d是一个整形指针(整形的地址就是指向整形的指针)
auto e = &ci;
//e是一种指向整形常量的指针(对常量对象取地址是一种底层const,会保留底层const)

如果希望auto推断出的是顶层const,可以这样做:

const auto f = ci;
//ci推演类型是int,f就是const int

----还可以将引用类型设为auto 此时原来的初始化规则仍然适用:

auto &g = ci;
//g是一个整形常量引用,绑定到ci
auto &h = 42;
//错误,非常量引用无法绑定字面值
const auto &j = 42;
//正确,可以为常量引用绑定字面值

设置一个类型为auto 引用时(auto &),值中的顶层常量的属性仍然保留,如果是类型auto的话,此时常量就不是顶层常量了(顶层const会被忽略)。

三、decltype类型指示符

-----有时候我们只想从表达式中获得它的类型,而不想给变量用表达式初始化,为满足这个要求,C++11新标准引入了第二种说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,但并不实际计算它的值。例:

decltype(f()) sum = x;
//sum 的类型就是函数f()返回的数据类型

假如函数 f() 返回类型为int,那么sum的类型为int。

decltype处理顶层const 和引用的方式与auto有一点不同,如果decltype 使用表达式是一个变量,则decltype返回该变量的类型(包含顶层const和引用在内):

const int ci = 0 , &cj = ci;
decltype(ci) x = 0;
//x 的类型const int
decltype(cj) y = x;
// y的类型 const int&, y绑定到变量x
decltype(cj) z;
// 错误,z的类型是const int&,所以z是一个引用,必须初始化

decltype和引用

—有些表达式向decltype返回一个引用类型:

//decltype的结果可以是一个引用类型
int i = 42, *p = &i, &r = i;
decltype(r + 0) b;
//正确,因为加法的结果是int,所以b是一个没有被初始化的int变量
decltype(*p) c;
//错误,c是int &,必须初始化

因为r是一个引用,因此decltype® 的结果是引用类型。如果想让结果类型是r的类型,可以把r当做表达式的一部分,如:r+0,显然这个表达式是一个具体的值而不是引用。

----另一方面,如果表达式的内容是解引用操作,则decltype 将得到的是引用类型。正如我们熟悉的那样,解引用指针可以得到指针所指向的对象,并且还可以给这个对象赋值,所以,decltype(*p) 的结果类型就是int &,而不是int。

decltypeauto还有一个重要的区别是: decltype 的表达式加上一个括号就会有不同的意思,如果该变量不加括号,则返回表达式的结果类型;如果给变量加上一层或多层括号,编译器将会把它当做一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样的decltype就会得到引用类型:

//decltype 的表达式如果加上了括号的变量,结果将为引用
decltype((i)) d;
//错误,d是类型是int &,必须初始化
decltype(i) e;
//正确,e是一个未初始化的int变量

注: 切记:decltype((varibale)) (主义是双层括号)的结果永远是引用,而decltype(variable)结果只有当variable本身就是一个引用时才是引用。


网站公告

今日签到

点亮在社区的每一天
去签到