C++ Primer 5 笔记 第二章 变量和基本类型

第二章 变量和基本类型

C++ 算术类型
bool, char, wchar_t, char16_t, char32_t, short, int, long, long long, float, double, long double.

字符型被分为三种:char, signed char, unsigned char. 但只有两种表现形式,带符号的和不带符号的。

选择类型的经验准则:
1.知晓数值不可能为负值时,选用无符号型。
2.使用int做整数运算,超过int表示范围时用long long,因为实际中short常显得太小,而long和int尺寸一样。
3.在算术表达式中,不要使用char或bool,只有在存放字符或者布尔值时才使用它们。即使使用,也应指明signed char 或者unsigned char。
4.执行浮点运算选择double。

把一个非布尔型的算术值赋给布尔类型时,初始值为0则
结果为false。否则为true。 0假非0真。

切勿混用有符号无符号:
当我们赋值给带符号类型一个超出他表示范围的值时,结果是未定义的。此时程序可能继续工作、可能崩溃、可能产生垃圾。
signed char c2=256;//c2的值时未定义的

signed u=10;
int i=-42;
std::cout<<u+i<<std::endl; //如果int占32位,输出2^32-32;

指定字面值类型
字符和字符串:加前缀u, U, L, u8;
整型和浮点型:加后缀u/U, l/L, ll/LL, f/F, l/L

变量:
初始化:创建变量时赋予其一个初始值,
赋值:把对象的当前值擦除,而以一个新值代替。

初始化的形式有:
int units_sold = 0;
int units_sold = { 0 };
int units_sold { 0 };
int units_sold ( 0 );
其中推荐第三种列表初始化方式,因为如果使用列表初始化方式且初始值存在丢失信息的风险,编译器将报错。

如果想声明一个变量而非定义它,就在变量名前添加关键字extern,而且不要显示地初始化变量:
extern int i; //声明i而非定义i
int j; //声明并定义j

变量命名规范:
1.标识符要提现其实际含义
2.变量名用小写字母;
3.自定义类名用大写字母开头;
4.如果标识符由多个单词组成,应该明显区分单词

当第一次使用变量时再定义。

允许内层作用域重新定义外层作用域已有的名字,但通过作用域操作符::可以覆盖默认作用域规则
     int unique = 0; // unique has block scope

     // output #1: uses global reused; prints 42 0
     std::cout << reused << " " << unique << std::endl;

     int reused = 0; // new, local object named reused hides global reused

     // output #2: uses local reused; prints 0 0
     std::cout << reused << " " <<  unique << std::endl;

     // output #3: explicitly requests the global reused; prints 42 0
     std::cout << ::reused << " " <<  unique << std::endl;

     return 0;

引用-左值引用
引用,为对象起别名。一旦引用,无法重新绑定到另一个对象上。
引用的类型必须要和与之绑定的类型严格匹配(有例外),并且只能绑定在对象上,不能与字面值或者表达式结果绑定。

指针域引用区别:
(1)指针本身就是一个对象;
(2)指针无需在定义是赋初始值。

* 称作解引用符

空指针
int *p1 = nullptr;     //等价于int *p1 = 0
int *p2 = 0;               //等价于将p2初始化为字面常量0
int *p3 = NULL;          //等价于int *p3 = 0 ,前提要#include cstdlib
最直接的方法是第一种方法,在新标准下现在的C++程序最好使用nullptr,同时尽量避免使用NULL。为什么呢?答案:
http://blog.csdn.net/langresser_king/article/details/8594279
http://blog.kingsamchen.com/archives/697

void*指针可以存放任意对象的地址。概括来说,以void*的视角来看内存空间也就仅仅是内存空间,没办法访问内存空间中所存放对象。

指向指针的引用
引用本身不是一个对象,因此不能定义指向引用的指针。但指针式对象,所以存在执行指针的引用。
int i = 42 ;
int *p ;          //p是一个int型指针
int *&r = p ;     //r是一个对指针p的引用
r = &i ;          //r引用了一个指针,因此给r赋值&i ,就是令p指向i
*r = 0 ;          //解引用r得到i,也就是p指向的对象,将i的值改为0
从右向左阅读r的定义,离变量名最近的符号(此例中是&r的符号&)对变量类型有最直接的影响,因此r是一个引用。

const限定符
read only ,const对象必须初始化。
默认状态下,const对象仅在文件内有效。解决这一情况的办法是无论声明还是定义,都添加extern关键字。

对常量的引用(简称 常量引用)
const int ci = 1024;
const int &r1 = ci;

引用的类型必须与其所引用对象类型一致,除非(1)(2)
初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成应用的类型即可。
int i = 42 ;
const int &r1 = i;          //允许将const int&绑定到一个普通的int对象上
const int &r2 = 42;     //正确,r1是一个常量应用

对const的引用可能引用一个并非const的对象。

指向常量的指针
底层const,不能用于改变其所指对象的值,指针所指对偶像是一个常量。
const double pi = 3.14;
const double *cptr = &pi;

常量指针
顶层const,必须初始化,一旦初始化完成,他的值就不能改变,即不变的是指针本身而非指向的那个值。
int errNumb = 0;
int *const curErr = &errNumb;     //curErr 将一直指向errNumb

常量表达式
由数据类型和初始值决定

将变量声明为 constexpr类型一遍由编译器来验证变量值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式值初始化。
constexpr int mf n= 20;
constexpr int limit = mf +1;
constexpr int sz = size();     //只有当size是一个constexpr函数是才是一条争取的声明语句。

尽管指针和引用都可以定义成constexpr,但他们的初始值却受到严格的限制。一个constexpr指针的初始值必须是nullptr或者0,或者存储于某个固定地址中的对象。

限定符constexpr仅对指针有效,与指针所指的对象无关:
const int *p =  nullptr;          //p是一个指向整型 常量的指针,底层const
constexpr int *q =nullptr;     //q是一个指向整型的 常量指针,顶层const

类型别名
定义类型别名,传统方法使用 typedef,新标准规定使用 别名声明using
typedef double wages;      //wage是double的同义词
using SI  = Sales_item;     //SI是Sale_item的同义词

typedef char *pstrings;
const pstrings cstr=0;     //cstr是指向char的 常量指针
const pstrings *ps;          //ps是一个指针,他的对象是指向char的 常量指针
const是对给定类型的修饰,上面基本类型都是const pstring,顶层const,而非直接替代后的const char *cstr。

auto类型说明符
让编译器替我们去分析表达式所属的类型
auto i = 0, *p = &i;     //i是证书,p是整形指针

auto一般会忽略顶层const
const int ci =i, &cr = ci;
auto b = ci;                     //b是一个整数,ci的顶层const被忽略
auto d = &i;                    //d是一个整型指针(整数的地址就是指向整数的指针)
auto e = &ci;                    //e是一个指向整数常量的指针(对常对象取地址是一种底层const)
const auto f = ci;          //ci的推演类型是int,f是const int

可以将引用类型设为auto,原来的初始化规则仍然适用:
auto &g = ci;               //g是一个整型常量引用,绑定到ci,顶层const
auto &h = 42;               //错误,不能为非常量引用绑定字面值
const auto &j = 42;     //正确

要在一条语句中定义多个变量,切记,符号&和*只从属于某个声明符,而非基本数据类型一部分
auto k = ci, &l = i;               //k是整数,l是整型引用
auto &m = ci, *p = &ci;     //m是对整型常量的引用,p是指向整型常量的引用
auto &n = i, *p2 = &ci;     //错误,i的类型时int,而&ci的类型时const int

C++ 11中引入的auto主要有两种用途:自动类型推断和返回值占位。auto在C++ 98中的标识临时变量的语义,由于使用极少且多余,在C++ 11中已被删除。auto自动类型推断,用于从初始化表达式中推断出变量的数据类型。通过auto的自动类型推断,可以大大简化我们的编程工作。

decltype类型指示符
返回操作数的数据类型
decltype处理顶层const和引用的方式与auto不一样,如果decltype使用表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)
需要指出的是,引用从来都最为其所指对象的同义词出现,只有在decltye处是个类外。

如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型。
int i = 42, *p = &i, &r = i;
decltype(r+0) b;     //正确,加法的结果是int,因此b是未初始化的int
decltype(*p) c          //错误,c是int&,必须初始化。
如果表达式的内容是解引用操作,则decltype将得到应用类型。正如我们所熟悉的那样,解引用指针可以得到指针所指的对象,还能给这个对象赋值。正因此,decltype(*p)的结果类型是int& ,而非int。

对于decltype所用的表达式来说,如果变量名加上一对括号(),则编译器就会把他当做表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样的decltype将会得到引用类型。
decltype((variable))的结果永远是引用

根据C++0x最终草案,decltype(e)所提取的类型由以下规则决定:
  1. 如果e是一个没有外层括弧的标识符表达式或者类成员访问表达式,那么decltype(e)就是e所命名的实体的类型。
  2. 如果e是一个函数调用或者一个重载操作符调用(忽略e的外层括弧),那么decltype(e)就是该函数的返回类型。
  3. 否则,假设e的类型是T:若e是一个左值,则decltype(e)就是T&;若e是一个右值,则decltype(e)就是T。
比如,
int a;
int f(void);
decltype(a) x1 = a;   //相当于 int x1 = a;(规则1,e是标识符)
decltype(f()) x2 = a;   //相当于 int x2 = a;(规则2,e是函数调用)
decltype((a)) x3 = a;  //相当于 int& x3 = a;(规则3,e是左值)
decltype(a+1) x4 = a; //相当于 int x4 = a;(规则3,e是右值)
 注意:decltype(e)中的操作数e仅用于推导类型,编译器不会计算e的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值