C++
读C++ Primer Plus
Ch1 : 预备知识
Ch2 : 开始学习C++
Ch3 :处理数据
基本类型没有绝对长度,依据不同实现而异
数据类型:
整型:char、short、int、long、long long
浮点型:float、double
新类型:
wcha_t(宽字符类型)、char16_t (16位无符号)、char32_t(32位无符号)
1 | char16_t ch1 = u'q'; |
整型溢出
1 | //suppose SHORT_MAX = 65535 |
Q :const和#define的区别?
类型转换:
种类:
- 将一种算数类型的值赋给另一种算术类型的变量时;
- 表达式中包含不同的类型时;
- 将参数传递给函数时。
具体规则:
- 初始化和赋值进行的转换,assign short to long,大范围转换成小范围可能会导致信息丢失,此时会警告
- 以{}方式初始化时进行的转换(C++11),不允许缩窄(即变量的类型可能无法表示赋给它的值)
- 表达式中的转换
- 传递参数的转换
- 强制类型转换,by
(typename) value
orstatic_cast<typename>(value)
,强制类型转换运算符const_cast
dynamic_cast
reinterpret_cast
static_cast
Ch4 :符合类型
Q : new和malloc区别?
A :new是运算符,malloc是库函数,new底层是malloc实现的,new类的时候会调用类的构造函数,malloc不会。
Q : 数组名和指针的区别?
A :数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
(1)修改内容上的差别
1 | char a[] = “hello”; |
(2) 用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p 所指的内存容量。C++/C 语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
1 | char a[] = "hello world"; |
Ch5 :循环和关系表达式
类型别名:
1 |
|
cin:
cin会忽略空格和换行符, cin.get(), cin.fail(), cin.eof()
Ch6 :分支语句和逻辑运算符
处理错误输入:
1 | while(!(cin >> golf[i])){ |
Ch7 : 函数
函数指针
Ch8 : 函数 进阶
Q :引用和指针的区别?
A :引用更接近const指针,必须中创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它。
名称修饰:
根据函数原型中指定的形参类型对每个函数名进行加密。
重载解析:
决定为函数调用那个一函数定义,大致过程:
- 创建候选函数列表
- 使用候选函数列表创建可行函数列表
- 确定是否有最佳的可行函数
模版函数的发展:
- 是什么类型,C++98无法判断
- decltype(C++11),
decltype(expression) var
, makes var the same type as result of expression - C++11后置返回类型
1 | template<class T1,class T2> |
Ch9 :内存模型和名称空间
Q :#include<>和 #inlcude””的区别?
A :使用<>编译器将在存储保准头文件的主机系统的文件系统中寻找,使用””,编译器将首先查找当前的工作目录或源代码目录,如果没有找到,就会在标准位置查找。
static的两种用法:
用于局部声明,以指出变量是无链接性的静态变量时,static表示的是存储持续性;
用于代码块外的声明时,static代表的是内部链接性。
/#ifndef :
预处理器编译指令,防止一个程序中多次包含同一个头文件
说明符和限定符:
volatile:告诉编译器
mutable:用它指出即使结构(或类)变量为const,其中某个成员也可被修改。
定位new运算符:
new的一种变体,使用时能指定要使用的位置。可以使用这种特性设置内存管理规程、处理需要通过特定地址进行访问的硬件或者特地位置创建对象。注意:如果指定的位置为静态存储区,不在delete的管辖范围之内,尝试使用delete释放该空间将会导致运行时错误。
Ch10 :对象和类
多态性:
多态性是指允许同一个函数(或操作符)有不同的版本,对于不同的对象执行不同的版本。C++支持以下两种多态性:
- 编译时的多态性,表现为函数名(或操作符)的重载;
- 运行时的多态性,通过派生类和虚函数实现。
作用域为类的常量:
在类内声明一个枚举
1
2
3
4
5
6class Bakery{
private:
enum {Months = 12};
double costs[Months];
...
}用这种方式声明枚举并不会创建类数据成员,也就是说,所有对象中都不包含枚举,另外,Months只是一个符号名称,在作用域为整个类的代码中遇到他时,编译器将用12代替他。
使用static声明
1
2
3
4
5
6class Bakery{
private:
static const int Months = 12;
double costs[Months];
...
}这将创建一个名为Months的常量,该常量与其他静态变量存储在一起,而不是存在对象中。因此,只有一个Months常量,被所有Bakery对象共享。
运算符重载
友元函数
Ch11 :使用类
Ch12 :类和动态内存分配
静态类成员:无论创建了多少对象,程序都只创建一个静态类变量副本
Ch13 :类继承
派生类和基类之间的特殊关系:
- 公有继承的派生类对象可以使用基类的共有方法
- 基类指针可以在不进行显式类型转换的情况下指向派生类对象,基类引用可以在不进行显式类型转换的情况下引用派生类对象
- 然而,基类指针或引用只能用于调用基类方法。==原因:==如果允许基类引用隐式地引用派生类对象,则可以使用基类引用为派生类对象调用基类的方法。这么做没有什么问题,但是如果可以将基类对象赋给派生类引用,==派生类引用能够为基对象调用派生类方法==,这么做是没有意义的,因为基类根本没有派生类方法。
为基类声明一个虚析构函数:
为了确保释放派生对象时,按正确的顺序调用析构函数。
动态联编:
编译器对非虚方法使用静态联编,对虚方法使用动态联编。
虚函数的工作原理:
虚函数表
虚函数的一些注意事项:
- 使用virtual指出
- 如果使用指向对象的引用或指针来调用虚方法。程序将使用为对象类型定义的方法。
- 如果定义的类将被用作基类,则应将那些要在派生类中重新定义的类方法声明为虚的。
- 其余:
- 类的构造函数不能是虚函数
- 基类的析构函数应该是虚函数,即使他不需要(当然如果类里没有虚函数就没有这个必须
- 友元不能是虚函数,只有成员才能是虚函数
- 若在派生类中对于某个虚函数重新定义,将会隐藏基类的声明
explicit用于转换函数,与构造函数一样,explicit允许使用强制类型转换进行显式转换,但不允许隐式转换。
valarray?的使用?
Ch14 :C++中的代码重用
has-a关系和is-a关系
包含和继承
MI(恕我直言我觉得MI这个东西太不科学了= =):虚基类以解决同一个类对象可能对应多个父对象的问题。
Ch15 :友元、异常和其他
异常处理:
- 使用abort()
- 返回错误码
- 异常机制(try、catch),栈解退
RTTI:
- dynamic_cast
- typeid
- type_info
Ch16 : string类和标准模版库
STL定义了5种迭代器:
- 输入迭代器
- 输出迭代器
- 正向迭代器
- 双向迭代器
- 随机访问迭代器
移动构造和移动赋值
序列容器类型:
- vector:通过随机访问进行快速访问
- list:强调元素的快速插入和删除
- queue
- deque
- stack
- array
- forward_list
关联容器:
- set
- multiset
- map
- multimap
无序关联容器:
- Unordered_set
- Unordered_map
- unordered_multiset
- Unordered_multimap
Ch17 :输入、输出和文件
Ch18 :探讨C++新标准
Q
- 为什么cin要比scanf慢?
- const常量的使用?
- 如何判断系统是64位的还是32位的?
- 多个cpp文件联合编译过程?
- 编译过程
- 函数调用实现过程?
- C++11标准?
- 32位系统和64位系统的指针大小不一样?
- printf参数?
- 运算符重载?
- 名称空间是如何识别的?
- 名称空间是控制访问权的一种方式
- const、static
- 强制类型转换
- 可类型提升,同种类型可向高级提升,非const可以提升为const,反之不可
- 变量命名风格
- 运算符优先级:
- !运算符优先级最高 > 算术运算符(乘除*, / > 加减+ , -)> 关系运算符(<= , < , > , >= , != , == ) > 逻辑运算符(&&,|| )
- 符号整型溢出
- 换行符
- unicode 字符集大小,ascii码自负
- 位运算应用
- STL
- 引起程序溢出的错误
- C++变量的存储不同区域(动态存储区、静态存储区
- iter
- 多态、继承,三大特性,五大原则
- how to avoid memory leak
- pointer是否支持—操作
- A:是的,支持,同++操作一样是移动一个指向类型的长度,两个指针可以相减,不过只在数组间的两个不同下标对应的指针管用,差值是下标差值
- 指针名和数组名的区别:(同:都可以使用方括号表示法,可以使用解引用运算符
- 可以修改指针的值,但数组名是常量
- 对数组应用sizeof运算符得到的是数组的长度,对指针应用sizeof得到的是指针的长度
- C++如何处理内存?
- 管理数据方式:(不同:严格限制了变量的寿命
- 自动存储,函数内部定义的常规变量
- 静态存储,整个程序执行期间都存在的存储方式,==使用栈?==
- 动态存储,new、delete所调用的空间,使得程序员对内存有更大的控制权,==使用堆?==
- 管理数据方式:(不同:严格限制了变量的寿命
- cin、cout如何处理字符?ios_base库的作用?
- 命名空间和头文件的区别?
- 【个人认为】命名空间的出现是为了解决两个文件中有相同函数命名引起的混淆,而如果只是include头文件,编译器检测到出现两个相同的函数将会报错。
- 函数重载,重载解析实现
- volatile?
- ifndef语句的作用?
- /#include 包含源代码文件会导致多重声明
- return引用和return值有什么不一样吗?(哦哦好像懂了
附1 :头文件说明:
climits
: 定义符号常量,用以表示类型的限制
cctype
: 字符相关的函数软件包,可以简化诸如确定字符是否为大写字母、数字、标点符号等工作,如isalpha(), isdigit(), tolower(), toupper()
附2 :标准库类介绍
1、cout
setf()
设置输出格式