C++ Primer 笔记 第二章

本文记录了C++ Primer第二章的学习笔记,涉及算术类型、Unicode字符、类型转换、字面值常量、变量、复合类型(引用与指针)、const限定符、auto与decltype,以及自定义数据结构的处理。

C++ Primer 笔记 第二章

C++会用是会用了,还是感觉基础不牢,于是励志从今天起开始每天看一点C++ Primer,争取到学期末时候把它精读完
这篇笔记仅记录了我感到不够熟悉或不够明确的部分,仅作个人学习记录

2021.3.29

第二章

2.1 基本内置类型

2.1.1 算术类型

一些不常用类型

类型含义最小尺寸
wchar_t宽字符16位
char16_tUnicode字符16位
char32_tUnicode字符32位
  • Unicode字符是用于表示所有自然语言中字符的标准
2.1.2 类型转换
类型转换
  • 给无符号类型赋超出其表达范围的值时,结果取余(即按位截断)
  • 给有符号类型赋超出其表达范围的值时,结果是未定义的undefined),此时程序可能继续工作,可能崩溃,可能产生垃圾数据
编程建议
  • 避免有符号无符号类型混用

  • 应避免依赖于实现环境的行为(不可移植) eg. 把int的大小看作一个确定不变的已知值

2.1.3 字面值常量
整型&浮点型
  • 十进制默认有符号,8/16进制可能有可能没有

  • 8进制: 0开头的整数 eg. 024

  • 16进制: 0x或0X开头 eg. 0x14

  • 浮点型: 默认为double,可以用小数/科学计数法表示,指数部分用E/e标识

字符&字符串
  • 字符——单引号

  • 字符串——双引号

    字符串在结尾处会自动添加一个空字符 ‘\0’

转义序列

不熟悉的符号:

符号含义
\a报警(响铃)符
\b退格符
\r回车符(return)
\f进纸符
指定字面值的类型
  • 字符&字符串:
前缀含义类型
uUnicode 16char16_t
UUnicode 32char32_t
L宽字符wchar_t
u8UTF-8(仅用于字符串)char
  • 整型:
后缀最小匹配类型
u / Uunsigned
l / Llong
ll / LLlong long
  • 浮点型:
后缀类型
f / Ffloat
l / Llong double

2.2 变量

2.2.1 变量定义

初始化不是赋值,初始化是创建变量时赋予其一个初始值,赋值是把对线的当前值擦除,并以一个新值来代替

  • 列表初始化(list initialization)

    //均可初始化一个名为unit_code的int变量
    int units_code{0};	//列表初始化
    //int u{2.333}		//编译报错,初始值存在丢失信息的风险
    int unit_code(0);
    int u(2.333)		//编译通过,丢失部分值
    
  • 默认初始化(default initialized)

    • 定义于任何函数体外的变量被初始化为0;
    • 定义证函数体内部的内置类型变量不被初始化,值为undefined,拷贝或访问它将引发错误
    • 每个类各自决定其初始化对象的方式,决定是否允许不经初始化就定义对象(若允许,则由类决定对象的初始值是什么)

建议初始化每一个内置类型的变量。

2.2.2 变量声明和定义的关系

C++支持分离式编程(separate compilation)机制,将声明(declaration)和定义(definition)区分开来,变量只能被定义一次,但是可以多次声明。若一个文件想使用别处定义的名字则必须包含对其的声明,即在变量名前添加关键字extern,例如extern int i;

extern若包含初始值则变成定义,例如extern double i=2.333;是定义而非声明

若在函数体内部,试图初始化一个extern标记的变量,会引发错误

  • C++是静态类型(statically typed)语言,在编译阶段检查类型,即进行type checking,故使用变量前必须声明其类型

2021.4.11

2.2.3 标识符
  • 命名规范:
    1. 能体现实际含义
    2. 变量名小写字母开头,命名格式为驼峰式(someName)或下划线形式(some_name)
    3. 自定义类名以大写字母开头
2.2.4 名字的作用域

显式访问全局变量:::variableName

2.3 复合类型

2.3.1 引用

引用主要指左值引用(lvalue reference)

引用为对象其了另外一个名字(即别名),引用类型必须被初始化,无法令引用重新绑定到另一个对象。

定义引用时程序把引用和它的初始值绑定在一起,而非拷贝初始值。

  • 引用并非对象,故不可定义引用的引用

2021.4.13

2.3.2 指针
  • 指针本身是对象,允许赋值和拷贝,无需赋初值
  • 若指针未被初始化则也将拥有一个不确定的值(此时为无效指针),拷贝/访问无效指针的值将引发编译器检查不到的错误

C++11标准引入nullptr来初始化指针
若想使用NULL则需#include <cstdlib>,相当于用0初始化指针。

  • 不可将int型的0直接赋值给指针
  • 现在的C++程序应最好使用nullptr,同时尽量避免使用NULL.
  • 建议初始化所有指针

void* 指针:

  1. 可存放任意对象的地址,对该地址中是什么类型的对象并不了解
  2. 无法访问且不可直接操作void*指针所指向的对象
2.3.4 理解复合类型的声明
  • 定义多个变量

    int* p1,p2;		//p1为int指针,p2为int
    
  • 指向指针的指针

    int i=1;
    int *pi=&i;
    int **ppi=&pi;	//ppi为一个指向一个int型指针的指针
    
  • 指向指针的引用

    int i=2;
    int *p=nullptr;
    int *&r=p;		//r为对指针p的引用
    
    r=&i;			//r指向i,即p指向i
    *r=3;			//修改r指向内容的值,即将i值改为3
    
  • 不可定义指向引用的指针(引用非对象)

  • 理解变量类型时,最简单的方法为从右向左阅读其定义,离变量名最近的符号对其类型有最直接的影响。

2021.4.22

2.4 const限定符

  • const对象必须初始化

  • 默认状态下,const对象仅在文件内有效

    若想在不同文件中共享const对象,则应在定义与声明时都添加extern关键字

2.4.1 const的引用
  • 可以引用const常量,但不可用作修改它的值

  • 不可将常量引用赋值给非常量引用

    int i=42;
    const int &r1=i;		//正确,r1为常量引用,不可通过r1修改i的值,但仍可以直接修改i的值
    const int &r2=r1*2;		//正确,r2也为常量引用
    int &r3=r1+1;			//错误,不可将常量引用赋值给非常量引用
    
2.4.2 指针和const
  • 想存放常量对象的地址,只能使用指向常量的指针(pointer to const),且不可用于改变其所指对象的值

  • 允许指向常量的指针指向一个非常量

    double x=1.23;
    double &y=x;
    const double *ptr=&x;	//正确
    //ptr=2;				//错误,不可通过ptr修改x的值
    x=3.21;					//正确,可通过其他途径改变x的值
    y=4.32;					//正确
    
  • const指针:

    • 常量指针(const pointer)必须初始化

      int x=1;
      int *const ptrx=&x;		//ptrx中存放的地址不变,可用于修改其中对象的值
      *ptrx=2;				//正确,x的值被修改为2
      const double y=2.19;
      const double *const ptry=&y;	//ptry中存放的地址不变,地址中存放的变量不变,
      								//即ptry为指向常量对象的常量指针
      
    • 从右向左阅读,例如const double *const ptry中,离变量名最近的为const表示其为常量对象,在这之后,*表示其为一个常量指针,double表示它是指向一个double类型的常量指针,最后,const表示它是一个指向一个double常量对象的常量指针

2021.4.23

2.4.3 顶层const

顶层const(top-level cosnt)表示指针本身是个常量

底层const(low-level const)表示指y所指的对象是一个常量

  • 执行拷贝操作时,顶层const不受影响,而拷入拷出的对象必须具有相同的底层const资格,或是两个对象的数据类型能够转换,一般来说,非常量可以转换为常量,反之则不行

定义中类型左侧为底层const,右侧为顶层const

2.4.4 constexpr和常量表达式

常量表达式(const expression)指值不会改变且在编译过程中就能得到计算结果的表达式,有数据类型和初始值共同决定

  • C++11新标准中允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式
constexpr int m=20;
constexpr int l=m+1;		//正确
constexpr int sz=size();	//仅当size是一个constexpr函数时才是正确的声明语句
  • 声明constexpr时的类型只能为“字面值类型”(literal type),目前为止接触过的字面值类型包括算术类型,引用,指针

  • 一个constexpr指针的初始值只能为nullptr或0,或是存储于某固定地址中的对象

    • 一般来说,函数体内定义的变量并非在固定地址中,constexpr指针不可指向主义的变量
    • 定义在所有函数体外的对象地址固定,可以用来初始化constexpr指针
  • constexpr把它所定义的对象置为了顶层const

    const int *p=nullptr;			//p是指向整形常量的指针
    constexpr int *q=nullptr;		//q是指向一个整数的常量指针(顶层const)
    constexpr int i=1;
    constexpr const int *r=&i;		//r是常量指针,指向整型常量i
    

2.5 处理类型

2.5.1 类型别名

传统方法:

typedef double wages,*p;		//wages是double的别名,p是double*的别名

新方法——别名声明(alias declaration)

using W = double;
  • 指针、常量和类型别名
typedef char *pstring;	//pstring=char*
const pstring *ps;
const char* *ps;		//与上一句等价

2021.4.25

2.5.2 auto类型说明符
  • auto定义的变量必须有初始值

  • 在一条语句中使用auto声明多个变量时,该语句中所有变量的初始基本数据类型必须一样

  • 在使用引用作为初始值时,以引用的对象的类型作为auto的类型

  • auto一般忽略顶层const,保留底层const

int i=0, &ir=i;
const int ci=1, &cr=ci;
auto a = &ci;		//a是指向常量的指针(底层const)
/*错误:*/const auto &b = 2;	//不可以将非常量引用绑定字面值
const auto *b = &ci;	//b是指向常量的常指针(顶+底)
2.5.3 decltype类型指示符

decltype选择并返回操作数的数据类型

decltype(func()) sum = x;		//并不实际调用函数func,只使用其返回类型
  • decltype返回包括顶层const与引用在内的所有属性
int m=1;
const int i=0, &ir=i;
double pi=3.14, *ptr=&pi;
decltype(ir) x=9;		//x的类型为const int&
decltype(pi+i) y;		//y的类型为double
decltype(ir+3) z;		//虽然ir类型为const int&,但加法表达式的结果为int,故z的类型为int
decltype(*ptr) w=4;		//w为double&,必须初始化
decltype((m)) a=9;		//a为int&,因为(m)被视为一种可以作为赋值语句左值的特殊表达式,得到引用类型
  • decltype((variable))的结果用于是引用

2.6 自定义数据结构

类内没有初始值的成员将被默认初始化(见2.2.1节)

类内初始值或放在花括号里,或放在等号右边,不可使用圆括号

  • 头文件通常只包含只能被定义一次的实体,如类、constconstexpr变量

预处理器(preprocessor)

  • 头文件保护符(header guard)

    #define 把一个名字设定为预处理变量

    #ifdef 当且仅当变量已定义时为真

    #ifndef 当且仅当变量未定义时为真

    一旦检查结果为真,则执行后续操作直至#endif指令为止,否则忽略中间部分所有语句

  • 头文件保护符必须唯一,一般做法是基于头文件名构建,并全部大写

#ifndef MAIN_H
#define MAIN_H

const int i=0;
#define PI 3.14

#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值