前言
上次看《C++ Primer》还是刚毕业出来工作那会,虽然当时看得比较快,但大体还是翻完了,毕竟自己是半路出家,收获还是很大的,当时的经理说我进步很大,这本书有很大的功劳。俗话说,温故而知新,坚持学习,天天向上。如今已经有了一定的开发经验,回过头来温习这本经典,对c++知识做进一步的学习。在此记录学习的要点,主要是针对个人的知识面做个记录,如,对自己不熟的点做记录,或者对有个用法结合自己的经验所产生的一些感想,并不是对该书所有内容做笔记。可能相关点记录不是特别详细,需要进一步了解可另外搜索相关资料看。当然还有就是c++20要出了,c++11都还没熟悉完,看的是第五版,已经是包含c++11的很多特性了。
内容会根据章节来记录,有些章节没什么内容就不做记录了,下面进入正题。
【第二章-变量和基本类型(上)】
1.算数类型
类型 | 含义 | 最小尺寸 |
---|---|---|
bool | ||
char | 字符 | 8位 |
wchar_t | 宽字符 | 16位 |
char16_t | Unicode字符 | 16位 |
char32_t | Unicode字符 | 32位 |
short | 短整型 | 16位 |
int | 整形 | 16位 |
long | 长整型 | 32位 |
long long | 长整型 | 64位 |
float | 单精度浮点数 | 6位有效数字 |
double | 双精度浮点数 | 10位有效数字 |
long double | 扩展精度浮点数 | 10位有效数字 |
其中wchar_t在win编程中用到比较多,当我们编写的win程序采用unicode,所有的win api涉及的字面值变量都是宽字符,当然后如果采用的是ASCII,还是用传统char,正常情况都是选用unicode的方式,这样显示非ASCII就不会出现乱码,比如中文。
还有long long是C++11新定义,这个类型一般用在64位程序中,现代机器64位已经很普及,当long无法满足,就使用long long
2.指定字面值类型
前缀 | 含义 | 类型 |
u | Unicode16字符 | char16_t |
U | Unicode32字符 | char32_t |
L | 宽字符 | wchar_t |
u8 | UTF-8(仅用于字符串字面常量) | char |
定义宽字符型字面值时前缀加L,如L"123",定义utf-8字符串字面值添加前缀u8,如u8“微软雅黑”,即采用utf-8编码字符,使用中文时采用u8的方式很有效
后缀 | 最小匹配类型 |
---|---|
u or U | unsigned |
l or L | long |
ll or LL | long long |
后缀 | 类型 |
f或F | float |
l或L | long double |
注意区别与上面的字符串字面值,这个是放在后缀,如42ULL,为无符号整形字面值,类型是unsigned long long;3.14159L,为扩展精度浮点型字面值,类型为long double
3.变量定义
定义变量时,最好给变量初始化,当变量未初始化时,编译器会根据变量类型赋予初值,这个初值可能不是我们想要的,当程序使用到这个变量就可能会出问题,所以都应该养成初始化变量的习惯。
定义并初始化变量一般采用等号,如int sum = 0;
看到这里使用=来初始化,有些人会觉得这是赋值。事实上在c++语言中,初始化和赋值是两个完全不同的操作。然而在很多编程语言中二者的区别几乎可以忽略不计,即使在c++语言中有时这种区别也无关紧要,所以人们特别容易把二者混为一谈。
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代
4.初始化列表
c++11支持初始化列表初始化的方式,即 使用花括号进行初始化,就和数组使用花括号初始化的方式一样
如
int sum = {0};
int sum{0};
int sum(0);
std::string str{"9999"};
std::vector<int> vec = {2, 2};
std::pair<int, float> testPair = {1, 1.1};
除了内置类型能够使用初始化列表,标准库的大部分容器都能够使用初始化列表,如vector、pair等
我们可以通过查看该类型的构造函数或者重载=函数是否支持传参initializer_list,如果支持initializer_list的传参即可使用初始化列表
//vector定义的initializer_list
vector(_XSTD initializer_list<value_type> _Ilist,
const _Alloc& _Al = allocator_type())
: _Mybase(_Al)
{ // construct from initializer_list
_Construct(_Ilist.begin(), _Ilist.end());
}
_Myt& operator=(_XSTD initializer_list<value_type> _Ilist)
{ // assign initializer_list
assign(_Ilist.begin(), _Ilist.end());
return (*this);
}
当然也可以通过initializer_list定义自己的类型支持初始化列表,我们看到Qt封装的容器也是支持了
//QList
QList(std::initializer_list<T> args)
//QVector
QVector(std::initializer_list<T> args)
QList<int> intList = {8, 9};
容器使用初始化列表,比使用传统的函数追加的方式简洁很多
5.变量声明与定义
为了支持分离式编译,c++语言将声明和定义区分开来。
声明使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。
定义负责创建于名字关联的实体
变量声明规定变量的类型和名字,在这一点上定义与之相同。但是除此之外,定义还申请了存储空间,也可能会为变量赋一个初始值
变量能且只能被定义一次,但是可以被多次声明
声明变量使用extern关键字,c++中建议不使用这种全局变量的方式,代码结构耦合度变高,具体用法就不介绍了,知道定义和声明是咋回事就够了
6.静态类型
c++是一种静态类型语言,其含义是在编译阶段检查类型。其中,检查类型的过程称为类型检查。对象的类型决定了对象所能参与的运算,在c++语言中,编译器负责检查数据类型是否支持要执行的运算,如果试图执行类型不支持的运算,编译器将报错并且不会生成可执行文件。程序越复杂,静态类型检查越有助于发现问题。然而,前提是编译器必须知道每一个实体对象的类型,这就要求我们在使用某个变量之前必须声明其类型。
反过来其他动态类型语言的数据类型在代码运行才会确定,数据类型绑定是代码运行的时候确定的。比如:JavaScript,php 。这些语言定义变量一般是var 变量名,这个变量可以赋各种类型的值。
上述的区别也可称为强类型定义语言和弱类型定义语言。
第二章剩下部分内容留在下一篇进行介绍。