【C++Primer】Notes

  • 第I部分:C++基础(2–7章)
  • 第II部分:C++标准库(8-12章)
  • 第III部分:面向对象设计(13–16章)

第二章 变量和基本类型

2.1 基本内置类型

2.1.1 算术类型

  • 整型:int bool char

  • 浮点型:float double

  • C++11: long long

    内置类型的及其实现:
    可寻址的最小内存块:字节(byte)大多数8bit
    存储的基本单元:字 (word) 由几个字节组成 32或64个byte
    每个字节与一个数字关联起来:地址(address)
    

    带符号类型和无符号类型

    char、signed char和unsigned char, char由(不同机器的)编译器决定是否有符号。所以不要用char进行算术运算。

    练习:2.1

2.1.2 类型转换

编译器会根据环境自动类型转换

  • 非bool->bool: 0为false, 非0为true;
  • bool->非bool: false=0, true=1;
  • 浮点数->integral: 保留整数部分;
  • 超出unsigned类型:高位丢失,也就是与所能表示的最大数+1的求余结果
  • 超出signed类型:结果是未定义的。可能崩溃。

负数补码:除了符号位,其他位取反+1

含有unsigned类型的表达式

unsigned u = 10; int i = -42;
cout << u + i;//会将int转化为unsigned, 结果是4294967264
//切记不要混用unsigned与signed

2.1.3 字面值常量

科学计数法:5e-6 = 5 x 10^-6

2.2 变量

2.2.1 变量定义

初始化不是赋值,初始化含义:创建变量是赋予其一个初始值,而赋值时把对象当前的值擦除,用新值代替.

C++11:列表初始化

值初始化:有括号

int i = 0;
int i = {0};
int i(0);
int i{0};
int i = int(10);//创建临时变量然后初始化i

默认初始化

int i;
int *i = new int;//无括号

2.2.2 变量声明和定义的关系

extern int i;//声明未定义
int j;//声明定义
//显式初始化
extern double pi = 3.14//定义

在函数内部初始化一个extern变量,会报错;

变量只能被定义一次,但可以多次声明。

只有定义了的变量才能赋值。

2.2.4 名字的作用域

C++中大多数作用域以{ }分隔,全局作用域::后接variable name.

2.3 复合类型

声明语句:base type + declarator(声明符)列表

2.3.1 引用

即左值引用。

  1. 无法重新绑定引用,引用必须被初始化;(因为一旦初始化引用,会与初始值的对象bind在一起)

  2. 不能定义引用的引用,可以定义引用的指针。(因为引用本身不是一个对象,只是已存在对象的别名)

  3. 除了引用P55和P534外,引用的类型必须与绑定的对象严格匹配。

2.3.2 指针

  1. 指针可以赋值和拷贝;(指针本身是一个对象)
  2. 无需再定义是赋初值;
  3. 不能定义指向引用的指针:int& *p;(因为引用不是对象,没有实际地址)
  4. 除了引用P56和P534外,pointer的类型必须与指向的对象严格匹配。

指针的值(地址)

  1. 指向一个对象;
  2. 指向紧邻对象所占空间的下一个位置;(数组的下标访问)
  3. 空指针:nullptr、0和NULL;(不指向任何对象)
  4. 无效指针,以上都不是(野指针)
建议初始化所有指针
如果使用未初始化的指针:
1.可能访问一个不存在的地址;
2.如果指针所占空间有内容,而这些内容又被当作地址,难以判断是否legal.

void*指针

用于存放任意对象的地址。

不能直接操作void*指针所指的对象,因为不知道这个对象到底是什么类型,也就无法确定能执行哪些操作。

2.3.3 理解复合类型的声明

指向指针的引用

int i = 42;
int *p;
int *&r = p; //r是一个对指针p的引用
r = &i;//给r赋值&i就是令p指向i
*r = 0;//解引用r得到i

要理解r的类型,应该从右往左读。

2.4 const限定符

because once after created a const object, it’s value can’t be changed, const object must be initialize.

const int i = get_size();//运行时初始化
const int j = 42; //编译时初始化
const int k; //error:k是一个未初始化的常量

初始化和const

主要限制就是只能在const类型的对象上执行不改变其内容的操作。

2.4.1 const的引用

初始化和const的引用

引用类型必须与其所引用对象的类型一致,第一种例外就是:在初始化常量时允许用任意表达式作为初始值,只要表达式的结果能转换成引用的类型即可。

int i = 42;
const int &r1 = i;//&i与&r1相同
const int &r2 = 42;//正确
const int &r3 = r1 * 2;//正确 &r3与&r1不同
int &r4 = r1 * 2;//error.r4是一个普通非常量引用
double dval = 3.14;
const int &ri = dval;//就是ri和dval的地址是不同的。
//为了确保ri bind一个int,编译器会将上诉代码转换
const int temp = dval;//临时int变量
const int &ri = temp;//让ri bind这个临时量

如果ri不是常量时,允许对ri赋值,这样改变的时临时变量,而不是dval,那么引用就没有意义了,所以这种情况是非法的。

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

常量引用只是对引用可参与的操作做出了限定,对于引用的对象本身是不是常量未作限定。因为对象也可能是非常量,所以允许通过其他方式改变它的值。

2.4.2 指针和const

point to const

指向常量的指针:不能用于改变其所指对象的值。

const double pi = 3.14;//pi是常量
double *ptr = &pi;//error.ptr是一个普通pointer
const double *cptr = &pi;//正确
*cptr = 42;//error.不能给*cptr赋值

指针的类型必须与其所指的对象必须是一个常量,但是有两个例外

第一种就是允许令一个指向常量的指针指向一个非常量对象:

double dval = 3.14;
cptr = &dval;//正确,但不能通过cptr修改dval

const pointer

常量指针:必须初始化,一旦初始化完成,它的值就不能再改变,像引用一样。

int errNumb = 0;
int *const curErr = &errNumb;//curErr将一直指向errNumb

2.4.3 顶层const

top-level const:指针本身是一个常量

low-level const:指针所指的对象是一个常量。

区别:

在执行对象的拷贝时:top-level const 执行拷贝操作拷入和拷出的对象是否是常量都没什么影响;

low-level const 执行对象拷贝,拷入和拷出的对象必须具有相同的底层const资格或者两个对象的数据类型必须能够转换,一般来说,非常量可以转化为常量。

练习:

2.30:Follwing sentences, please explain the object is top-level const or low-level const?

const int v2 = 0; //top
int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = & v2, *const p3 = &i, &r2 = v2;//p2-low p3-top r2-low

2.31: 对于上一个练习,下列语句是否合法?

r1 = v2;//legal. 拷贝赋值实际修改v1的值。
p1 = p2;//illegal. p1是normal pointer,p2是low-level const,这样可能会错误的改变常量的值。
p2 = p1;//legal. p2可以指向非常量,但不能通过p2更改它所指的值
p1 = p3;//illegal. p3包含low-level const
p2 = p3;//legal. p2和p3包含相同的底层const

2.4.4 constexpr和常量表达式

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

字面值属于常量表达式,用常量表达式初始化const对象也是常量表达式。

const int max_files = 20;//yes
const int limit = max_files + 1;//yes
int staff_size = 27;//no 非const
const int sz = get_size();//no 直到运行时才能获取到具体值。

constexpr变量

必须用常量表达式初始化:

constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr innt sz = size();//只有当size是一个constexpr函数时,才正确。

指针和constexpr

限定符constexpr仅对有效,与指针所指的对象无关:

const int *p = nullptr;//p is point to const
constexpr int *q = nullptr;//q is const point

constexpr 既可以指向常量也可以指向非常量。

int j = 0;
constexpr int i = 42;
//i和j必须定义在函数体外,因为
constexpr const int *p = &i;//p是常量指针常量,指向int常量i,不可修改指向和指向的值
constexpr int *p1 = &j;//p1是常量指针,指向integer j

2.5 处理类型

2.5.1 类型别名

类型别名是某种类型的同义词。使复杂的类型名字变得更简单。

  1. typedef

    typedef double wages;
    typedef wages base, *p;//p是double*的同义词
    
  2. using

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

2.5.2 auto类型说明符

auto声明的类型必须有初始值,声明多个变量,则所有变量的初始基本数据类型必须一样。

auto i = 0, *p = &i; //right. i是整数,p是int*
auto sz = 0, pi = 3.14;//error. sz与pi类型不一致
  1. 当引用作为出世之时,参与初始化的其实是引用对象的值。

    int i = 0, &r = i;
    auto a = r;//a是一个整数
    
  2. auto会忽略top-level const , 同时low-level const 会被保留。

    const int ci = i, &cr = ci;
    auto b = ci;//b是int(顶层const被忽略)
    auto c = cr;//c是int(cr是ci的别名,ci本身是一个顶层const)
    auto d = &i;//d是一个整型指针(整数的地址就是指向证书的指针)
    auto e = &ci;//e是一个point to const int 的指针(对常量对象取地址是一个底层const)
    
  3. 如果希望推断出auto类型是一个顶层const, 需要明确指出

    const auto f = ci;//f是const int
    
  4. 引用的类型设为auto

    auto &g = ci;//g是整型常量引用
    auto &h = 42;//error: 不能为非常量引用bind字面值
    const auto &j = 42;//可以为常量引用绑定字面值
    
  5. auto引用,初始值的顶层常量属性被保留

    auto k = ci, &l = i;//k是int l是int&
    auto &m = ci, *p = &ci;//m是cosnt int &, p是const int *
    auto &n = i, *p2 = &ci;//error. i的类型是int而&ci的类型是const int
    

2.5.3 decltype 类型指示符

为了满足从表达式推断出要定义的变量的类型,但是不想使用表达式的值初始化变量。

编译器只会分析表达式结果的类型,并不计算值。

decltype(f()) sum = x;//sum的类型就是函数f的返回类型,不会调用函数,

decltype处理变量,则decltype返回该变量的类型(包括顶层const和引用在内)

const int ci = 0, &cj = ci;
decltype(ci) x = 0;//x是const int
decltype(cj) y = x;//y是const int&, y bind x
decltype(cj) z;//error. z是const int&, 必须初始化

decltype 和引用

有些表达式将返回一个引用:

int i = 42, *p = &i, &r = i;
decltype(r + 0) b;//未初始化的 int 而decltye(r)是一个引用
decltype(*p) c;//error. c是int&, 必须初始化
decltype((i)) d;//error,d是int& 必须初始化

结论:decltype返回表达式结果对应的类型,r+0的结果是int;

解引用操作,decltype将得到引用类型;

如果表达式是加了括号的变量,结果是引用。

2.6 自定义数据结构

2.6.3 编写自己的头文件

预处理器概述

头文件保护符

#ifndef xxx
#define xxx
#include <iostream>
...
#endif

第三章 字符串、向量和数组

3.2 string

可变长的字符序列。string包含在namespace std中。

#include <string>
using std::string;

3.2.2 string对象的操作

string的操作含义
os << s将s写到输出流os当中,返回os
is>>s从is中读取字符串赋给s,字符串以空白分隔,返回is
getline(is,s)从is中读取一行赋给s,返回is
s. empty ()s为空返回true,否则返回false
s.size ()返回s 中字符的个数
s [n]返回s中第n个字符的引用,位置n从0计起
sl+s2返回s1和s2连接后的结果
s1=s2用s2的副本代替s1中原来的字符
s1==s2 s1!=s2如果s1和s2中所含的字符完全一样,则它们相等;string对象的相等性判断对字母的大小写敏感
<,<=, >,>=利用字符在字典中的顺序进行比较,且对字母的大小写敏感

第六章 函数

6.5.2 constexpr 函数

约定:

  1. 函数的返回类型即所有形参都是字面值类型;
  2. 函数体中只有return 语句。

6.7 函数指针

第十二章 动态内存

12.1 动态内存与智能指针

12.1.1 shared_ptr 类

shared

虚继承:
[https://www.cnblogs.com/weekbo/p/8384943.html]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值