基于c++ primer plus的读书笔记
c语言部分
基本函数构成
将数组传递为函数参数
1 | int fcname(int arg[],int n) |
基本输入输出
1 | - cin及其衍生函数返回一个iostream函数的引用,即支持 |
文件输入输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14写入文件
ofstream fout;//ofstream继承ostream
fout.open("hello.txt");
fout << "i'm adding sth"
|| ofstream fout("hello.txt");
读取文件也类似
fin >> ch||string
关闭流
fout.close()
fin.close()
检测文件是否打开
if (!fin.is_open())
设置文件输入输出格式
ios_base::
基本逻辑运算符
break打断循环 continue,跳到更新表达式前开始执行 非const引用的函数不接受const参数
基本数据类型
结构数组
1 | stname stobj\[int x] = |
名称空间
1 | #ifndef HNAME_H |
如果在遇到另一个定义HNAME_H的头文件时,将他忽略
作用域: 1默认情况下,函数中声明的变量作用域位于代码块内,如果函数内外都声明一个同名变量,运行至内部代码块使用内部,离开代码块使用外部 2静态变量存在于整个程序运行周期,脱离作用域后只是无法使用并不消失 代码块外声明且不带static关键字:链接性外部,可以在其他程序使用 代码块外声明,且使用static:链接性内部,可以在整个程序使用 代码块内声明,且使用static:作用域于代码块内,但始终存在//由于静态变量只可以定义一次,所以即使离开代码块后变量依旧存在,且值不变,直到下一次修改 3运算符::放置于变量前时,使用同名变量(如果有)的全局版本 4namespace{
} 无法放置于代码块内,因此默认为全局名称,可以囊括声明和定义,可以随时添加 定义于类声明的函数自动成为内联函数
c++特性
class
1声明构造函数时,尽量使用explicit(显性转换)前缀,防止隐性转换带来的问题 mutable(摆动的)前缀声明变量,表示这些变量可能在const成员函数内被更改 用const_cast<>和static_cast<>与this指针可以实现const成员函数向非const的转变,反之则是错误的
2class初始化成员时,按构造函数声明变量的顺序,因此初始化成员时最好也以此顺序初始化 如果不希望class有copy和赋值(=)操作,则应该在private里定义copy和=运算符
3基类引用可以指向派生类对象,无需进行强制类型转换
4定义于类声明的函数自动成为内联函数
5类的函数对所有对象共用,但数据则各自私有
6要创造类对象数组,该类必须有默认构造函数
7只有一个构造函数参数的构造函数可以用于类的自动转换 classname t; t=20; 如果想禁止这种转换,可以声明explicit给构造函数
8类声明中可定义对于某种基本类型的转换函数 operator int();//可声明为显式转换,尽量避免过多的转换造成二义性
9如果定义类成员参数为static,则它在程序中只有一个地址,可以被所有类成员共享 但通过static实现共享成员时,需要重新定义复制和赋值函数来避免问题
动态类的注意事项
*构造函数中如果用new初始化指针成员,则应该在析构函数中使用delete new对应delete,new[]对应delete[] 对多个构造函数,应用和析构函数兼容的new来初始化成员 重构复制和赋值运算符来实现深复制
10对于使用new创建的类,使用delete时其析构函数才会被调用 如果在使用new时,将对象地址赋予一个指针时,如果删除指针,则对应的对象会调用自己的析构函数 对与使用定位new创建的类对象,需要显式调用析构函数 object->~classname(); 且应该以创建顺序的相反顺序调用,因为后创建的对象可能依赖于前者
类继承
公有继承
class sonclassname: public fatherclassname 派生类继承了基类的公有接口和数据 但只能用基类public和protected函数访问基类私有数据 派生类可添加函数和数据成员 派生类需要自己的构造函数,并由于权限问题,其构造函数必须包括基类构造函数,并且同样可以使用成员初始化列表 指针
基类指针和引用可以在不显式转化的情况下指向派生类对象反过来却不行 虚函数
- 对于基类和派生类的同名函数: 如果函数通过引用或指针调用,将确定使用哪种方法 ¥如果没有使用关键字virual,将根据引用类型或指针类型选择方法。 如果使用了关键字virtual,将根据引用或指针指向对象的类型选择方法
- 构造函数不能为虚函数
- 析构函数应当为虚函数
- 友元函数并非类成员,但可以使用虚函数
- **重新定义继承方式(虚实)并非重载,会覆盖掉原先的虚函数定义,如果必须重新定义,则需要重新定义使用基类虚函数
纯虚函数
virual typename func() const=0; 含有虚函数的类不能创建实例,只能用作基类
访问控制(protected)
派生类成员函数可以访问protected成员,不能访问private成员
私有继承
使用私有继承,基类的公有成员和保护成员都成为派生类的私有成员,只可以在派生类的成员函数中使用,可以实现has_a关系 私有继承访问基类方法时需要调动基类的命名空间 访问基类对象
如果要直接访问基类对象,则需要调用强制类型转化将派生类转化为基类
保护继承
保护继承时,基类的公有和保护成员都成为派生类的保护成员,基类接口在派生类中可用
通过using指令可以让私有函数被当前作用域可用
命令行参数
int main(int argc,char* argv[]) argc为参数个数 argv为参数组成的字符串
字符输入
1 | cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流) |
1 | cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流) |
<string> 重载符号+实现拼接 str.size() 输入字符串使用getline(cin,str) 结构数组 struct stname; stname stobj[int x] = { {} {} } 字符函数库<cctype> isspace(ch)测试是否空白 isalpha(ch)是否字符 isdigit()是否数字 ispunct()是否标点
指针
1 | 1,c++没有溢出检测机制, |
智能指针
auto_ptr<string> 和<unique_ptr>指针采用所有权模型,对特定对象只有一个智能指针可以拥有它,只有拥有它的指针可以删除它 shared_ptr<string>追踪引用对象的智能指针数量,最后一个指针过期时才会调用delete 使用new分配内存才能使用auto_ptr,unique_ptr
异常
try_catch
1 | try{ |
栈解退
假设try块没有直接调用引发异常的函数,而是调用对引发异常的函数进行调用的函数,则程序从引发异常的函数跳到包含try块和处理程序的函数(追踪到一个地址位于try块的返回地址) 其他异常特性
- throw-catch类似函数参数和返回,但函数返回语句将控制器交给调用函数的函数,但throw语句将控制权向上返回到第一个这样的函数,包含能捕获相应异常的try-catch组合
- throw语句总是生成副本,但catch参数使用基类引用能捕获所有派生类的异常对象
exception类
exception类可作为其他异常类的基类,用what的虚函数(返回一个字符串)重载来指示错误类型 失败时返回空指针的语法
1 | int * pi= new (std::nothrow) int; |
未捕获异常
未捕获的异常会使程序调用函数terminate(),默认情况下,terminate()调用abort()函数,可以指定terminate()调用的函数来修改其行为
一些新特性
关键字
关键字nullptr表示空指针
RTTI(运行阶段类型识别)
dynamic——cast
danamic_cast<type *> (pt) 如果可以安全将pt转化为type*指针,返回对象地址,否则返回空指针 如果对引用使用,错误时返回bad_cast异常
typeid和type_info
typeid返回对type_info对象的引用,type_ifo是定义在typeinfo的类,重载==和!=预算符,例如 typeid(obj1)==typeid(obj2)
类型转换运算符
- dynamic_cast
- const_cast
- static_cast
1 | //用于执行各种类型的数值转换static_cast <typename> (expression) |
- reinterpret_cast /执行危险的转换
移动语义 通过指针转移右值的地址给新对象 或通过std::move()将左值转化为右值
someclass()=default default关键字显式声明编译器创建默认构造函数,复制构造函数 delete用于禁止类中的函数
关键字override可用于覆盖虚函数定义
匿名函数
返回类型编译器自动确定,可直接作为函数指针使用
1 | [] (double x) {return x%3==0;} |
可以返回类型后置
1 | [] (double x)-> double{int y = x;return y-x;} |
可以给匿名函数命名