C++基础 Chapter 2

1.指向指针的引用

引用本身不是一个对象,不能定义指向引用的指针;指针是对象,所以存在对指针的引用

int i = 42;
int *p;
int *&r = p;    //r是对指针p的引用

r = &i;    //r引用了一个指针,因此给r赋值&i就是令p指向i
*r = 0;    //将i的值改为0

2.const限定符

  • const对象必须初始化,初始值可以是任意复杂表达式
  • 默认状态下,const对象仅在文件内有效
  • 某些时候需要多文件使用某个const对象,则只需要在不管是声明还是定义之前都添加extern关键字即可,这样定义一次就好

(1)const的引用

一般情况下,引用的类型必须与其所引用对象的类型一致,但有两种情况例外:

第一种:在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可,

int i = 42;
const int &r1 = i;    //true,允许将const int&绑定到一个普通int对象上
const int &r2 = 42;    //true,r2是一个常量引用
const int &r3 = r1 * 2;    //true,r3是一个常量引用
int &r4 = r1 * 2;    //false,r4是一个普通的非常量引用

(2)指针和const

指向常量的指针不能用于改变其所指对象的值,要想存放常量对象的地址,只能用指向常量的指针:

const double pi = 3.14;
double *ptr = pi  //flase,ptr是一个普通指针
const double *cptr = pi   //true,cptr可以指向一个双精度常量
*cptr = 42; //false,不可给*cptr赋值

(3)顶层const

顶层const表示指针本身是个常量;底层const表示指针所指的对象是个常量。

更一般的,顶层const可以表示任意的对象是常量,这对任何数据类型都适用,比如算数类型、类、指针等。

底层const则与指针和引用等复合类型的基本类型部分有关。

int i = 0;
int *const p1 = &i;    //不能修改p1的值,顶层const
const int ci = 42;    //不能修改ci的值,顶层const
const int *p2 = &ci;    //可修改p2的值,底层const
const int *const p3 = p2;    //靠右的是顶层const,靠左的是底层const
const int &r = ci;    //用于声明引用的const都是底层const

进行拷贝操作时:

  • 顶层const不受什么影响

  • 拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换,一般非常量可以转换为常量,反之不行!

int *p = p3;    //false,p3包含底层const定义,p没有
p2 = p3;    //true,p2和p3均是底层定义
p2 = &i;    //true,int*可以转换为const int*
int &r = ci;    //false,普通的int&不能绑定到int常量上
const int &r2 = i;    //true,const int&可以绑定到一个普通的int上

(4)constexpr和常量表达式

常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式

constexpr变量

C++11中,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式,声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化:

constexpr int mf = 20;    //20是常量表达式
constexpr int limit = mf + 1;    //mf+1是常量表达式
constexpr int sz = size();    //只有当size是一个constexpr函数时,才是一条正确的声明语句

charpter 6中将介绍新标准允许定义一种特殊的constexpr函数,该函数足够简单以使得编译时就可以计算其结果

字面值类型

一个constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象。

函数体中定义的变量一般并非存放在固定地址中,因此constexpr指针不能指向这样的变量,相反的,定义在函数体之外的对象其地址固定不变,能够用来初始化constexpr指针。(charpter 6中将介绍函数定义一类有效范围超出函数本身的变量,他们在函数体之外也有固定地址)

指针和constexpr

在constexpr声明中如果定义了指针,限定符constexpr仅对指针有效,与指针所指的对象无关

const int *p = nullptr;    //p是指向整型常量的指针
constexpr int *q = nullptr;    //q是指向整数的常量指针

constexpr会将他所定义的对象置为顶层const,constexpr指针既可以指向常量也可以指向非常量:

constexpr int *np = nullptr;    //np是指向整数的常量指针,其值为空
int j = 0;
constexpr int i = 42;    //i的类型是整型常量
//i和j必须定义在函数体之外;
constexpr const int *p = &i;    //p是常量指针指向整型常量i
constexpr int *p1 = &j;    //p1是常量指针,指向整数j

3.处理类型

(1)类型别名

有两种方法定义类型别名:

第一种:使用typedef

第二种:使用别名声明(C++11)

using SI = Sales_item;    //SI是Sales_item的同义词

using作用是将=左侧的名字规定成右侧类型的别名。

(2)指针、常量和类型别名

typedef char *pstring;    //类型pstring实际上是类型char*的别名
const pstring cstr = 0;    //cstr是指向char的常量指针
const pstring *ps;    //ps是一个指针,它的对象是指向char的常量指针

当遇到使用类型别名的的声明语句时,不可将类型别名替换成它本来的样子

const char *cstr = 0;    //则声明了一个指向const char的指针。

4.auto类型说明符

C++11引入auto类型说明符,它可以让编译器替我们去分析表达式所属的类型

auto定义的变量必须具有初始值,它能在一条语句中声明多个变量,但是要求该语句中所有变量的初始基本数据类型必须一样:

auto i = 0, *p = &i;    //true,i是整数,p是整型指针
auto sz = 0, pi = 3.14    //false,sz和pi的类型不一致

复合类型、常量和auto

  • auto一般会忽略掉顶层const,同时底层const会保保留下来,当初始值是一个指向常量的指针时:
const int ci = i, &cr = ci;
auto b = ci;    //b是整数(ci的顶层const特性被忽略)
auto c = cr;    //c是整数(ci本身是一个顶层const)
auto d = &i;    //d是一个整型指针(整数的地址就是指向整数的指针)
auto e = &ci;    //e是一个指向证整数常量的指针(对常量对象取地址是一种底层const)
  • 需要推断出的auto类型是一个顶层const时
const auto f = ci;    //ci推测的类型是int,f是const int
  • 可将引用的类型设为auto,此时原来的初始化规则仍然适用
auto &g = ci;    //true,g是整型常量引用,绑定到ci
auto &h = 42;    //false,不能为非常量引用绑定字面值
const auto &j = 42    //true,可以为常量引用绑定字面值

注:设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留

  • 要定义多个变量时,符号&和*只从属某个声明符,而非基本数据类型一部分,所以初始值必须是同一类型

5.decltype类型提示符

作用:选择并返回操作数的数据类型(过程中编译器分析表达式得到类型,并不实际计算出表达式的值)

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

如果decltyoe使用的表达式是一个变量,则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;        //false,z是一个引用,必须初始化

decltype和引用

如果表达式不是一个变量,则decltype返回表达式结果对应的类型

//decltype的结果可以是引用类型
int i = 42, *p = &i, &r = i;
decltype(r+0) b;    //true,加法的结果是int,所以b是一个未初始化的int
decltype(*p) c;    //false,c是int&,必须初始化

如果表达式的内容是解引用操作,则decltype将得到引用类型

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

//decltype的表达式如果是加上了括号的变量,结果将是引用
decltype((i)) d;    //false,d是int&,必须初始化
decltype(i) e;    //true,e是一个未初始化的int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值