C++设计语言(第四版)读书笔记(1)第1-3章

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YuYunTan/article/details/84591456

书籍信息

  名字:C++程序设计语言:第1~3部分(原书第4版)
  作者:Bjarne Srtoustrup
  出版社:机械工业出版社

笔记内容

  1、bool,char,int,double四类,与硬件特性直接相关,尺寸固定不变,决定其中所能存储的值的范围
  2、char变量尺寸取决机器存储字符所需空间(通常8字节),其他类型是char的整数倍。类型实际尺寸依赖于实现
  3、c++初始化除了=,还可以使用花括号{}内的一组初始化器列表,使用花括号时=号是可选
  4、花括号初始化至少确保不会发生某些可能导致信息丢失的类型转换
  5、常量声明必须初始化,普通变量极有限情况下不初始化,用户定义类型,string,vector,Matrix,Motor_controller和Orc_warrior可以在定义时进行隐式初始化
  6、使用auto可以由初始化器推断得到,无需显示指定类型。没有理由需要显式指定数据类型,使用auto
  7、常量:const修饰,承诺不改变该值,主要用于说明接口,变量传入函数不需担心变量会在函数内部改变。constexpr,在编译时求值,主用于说明常量,作用是允许数据置于只读内存中(不太可能被破坏)以及提升性能。
  8、const修饰函数参数列表的变量,表明函数不会改变其值。constexpr是常量表达式,在表达式编译时求值,不能使用变量可以使用常量(const)的表达式。定义为constexpr的函数必须简单。constexpr函数可接受非常量实参,非常量表达式实参可调用constexpr函数。
  9、声明运算符:[]表示"…的数组", * 表示"指向…",&表示"…的引用"
  10、前置一元运算符*表示"…的内容",前置一元运算符&表示"…的地址"

  11、范围for语句

int v [] = {0,1,2,3,4,5}
for(auto x:v)
	cout<<x<<'\n';
for(auto x:{10,22,33})
	cout<<x<<'\n';
for(auto &x :v)// x不是拷贝值,而是指向v中的元素
    ++x;

  12、没有可用对象将指针取值为nullptr,所有指针类型都共享一个nullptr

  13、new运算符从一块名为自由存储(堆,动态内存)的区域分配内存

  14、访问struct成员,一种是名字或引用,通过点运算符访问,另一种是指针,->访问。

  15、结构是组织元素数据的数据结构,可自由使用其数据部分。

  16、类,构建类型易于修改和使用,数据使用具有一致性,并且表达形式最好对用户不可见。

  17、构造函数可用成员初始化器列表来初始化类成员。

  18、enum class Color{red,blue,green},像枚举类,Color是其指定作用域。该定义是强类型的enum

  19、声明来描述接口,声明指定使用某个函数或某种类型所需的所有内容。

扫描二维码关注公众号,回复: 4444537 查看本文章

  20、C++支持分离变异,用户代码只能看到所用类型和函数声明,定义则放置在分离的源文件,被分别编译。优点是编译时间减到最少,并且强制要求程序中逻辑独立部分分离开来。

  21、假定某事为真的声明称为类的不变式(class invariant),简称为不变式(invariant)。建立类不变式是构造函数的任务(从而成员函数依赖于该不变式),当成员函数退出时,类不变式依然成立。

  22、new运算符找不到可分配内存,会抛出std::bad_alloc异常。

  23、不变式是构造函数和析构函数支撑的资源管理概念的基础。

  24、static_assert机制能用于任何可以表达为常量表达式的东西。static_assert(A,S),A不为true,则S作为一条编译器错误信息输出。

  25、static_assert最重要的用途是为泛型编程中作为形参的类型设置断言。

  26、模板是一种用(其他)类型和算法对类型和算法进行参数化的机制

  27、具体类基本思想是其行为像内置类型一样的类。典型特征是其表现形式是其定义的一部分。

  28、定义在类内部的函数被认为是内联的。

  29、类内函数的const修饰,比如f()const,表示不会修改所调用的对象,即对象的成员不能被更改。

  30、容器是指包含若干元素的对象。

  31、构造函数中请求资源,在析构函数中释放它们的技术称为资源获取即初始化(Resource Acquisition Is Initialization,RAII)

  32、容器初始化,可用初始化器列表构造函数:使用元素的列表进行初始化。或push_back():在序列末尾添加新元素。

  33、抽象类型将使用者和类的实现细节完全隔离。虚函数virtual修饰,表示可能随后在其派生类中重新定义,如果写virtual f()=0,则表明是纯虚函数。含有纯虚函数的类称为抽象类。

  34、编译器将虚函数的名字转换成函数指针表中对应的索引值,这张表称为虚函数表(virtual function table,vtbl)。每个含有虚函数的类都有其的vtbl用于辨识虚函数。vtbl中的函数确保对象被正确使用。

  35、类层次提供两种便利:接口继承和实现继承。

  36、当对象的unique_ptr离开作用域,unique_ptr将释放掉所指向的对象。

  37、类对象的拷贝操作:拷贝构造函数和拷贝赋值运算符。但拷贝容量过大,且不需要中间结果,采用移动拷贝构造函数,参数列表带有两个&。

  38、符号&&表示“右值引用”,给该引用绑定一个右值。左值表示为能出现在赋值运算符左侧的内容,右值是无法为其赋值的值(比如函数调用返回的一个整数),右值引用是引用别人无法赋值的内容。当右值引用被用作初始化器或者赋值操作的右侧运算对象,则程序使用移动操作。

  39、使用移动拷贝函数来执行从函数中移出返回值的任务。移动拷贝构造函数允许对象从一个作用域简单便捷移动到另一个作用域。

  40、标准库函数 move()返还实参的右值引用。

  41、unique_ptr代表智能指针,就是资源句柄。

  42、可以把指针转化为资源句柄,能实现强资源安全。可以消除资源泄露。换句话说,对于一般概念上的资源,这种方法可以消除资源泄露,比如存放内存的vector,存放系统线程的thread和存放文件句柄的fstream。

  43、尽量避免使用默认拷贝和移动,最好删除掉(函数后面写=delete)。

  44、如果使用者在类中显式声明析构函数,则移动操作不会隐式生成。

  45、定义参数化类型模板 templaye<typename T>,模板是编译时的机制,不会产生额外运算开销。

  46、模板特殊用途是函数对象,可以像调用函数一样使用函数对象。函数对象精妙在于随身携带准备与之比较的值,无需为每个值单独编写函数,更不必保存到全局变量中。

template<typename T>
class Less_than{
    const T val;//待比较值
public:
    Less_than(const T &v):val(v){}
    bool operator()(const T &x)const{return x<val;}//调用运算符
}

  然后代码中比较使用:

Less_than<int> lti(42);
Less_than<int> lsi{"Backus"};
bool b1 = lti(n);// 比较n和42
bool b2 = lsi(s);// 比较s和“Backus”

  函数对象的示例

template<typename C,typename P>
int count(const C &c,P pred ){
    int cnt = 0;
    for(const auto &x:c)
        if(pred(x))++cnt;
    return cnt;
}

  这么调用减少局部变量的使用

cout << "number of values less than"<<x<<":"<<count(vec,Less_than<int>{x};

  47、用于指明通用算法关键操作含义的函数对象(Less_than之于count())被称为策略对象

  48、[&](int a){return a<x;}被称为lambda表达式,用于生成函数对象,就像 Less_than<int>{x}一样。

  • [&]是一个捕获列表,它指明所用局部名字(如x)将通过引用访问。如果希望只捕获x,则可以写成[&x],如果希望给生成的函数对象传递一个x的拷贝,则写成[=x]。
  • 什么也不捕获是[]
  • 捕获所有通过引用访问的局部名字是[&]
  • 捕获所有以值访问的局部名字是[=]

  49、函数对象(尤其是lambda)能在一定成都上解决这一问题,其核心思想把容器遍历和对每个元素的具体操作分离开来。

  示例:lambda使用

  定义某个操作用于指针容器的元素所指的每个对象

template<class C,class Oper>
void for_all(C & c,Oper op)//C 是指针容器
{
 	for(auto &x:c)
    	op(*x);
}

  然后使用时:

for_all(v,[](Shape & s){s.draw();});//draw_all();
for_all(v,[](Shape &s){s.rotate(45);});// rotate_all(45)

  50、可变长参数模板。即令其可接受任意数量任意类型的实参,称为可变参数模板。<template><typename T,typename ... Tail>

  关键是:当传入多个参数,注意第一个和其他参数区分对待。

  优势:接受希望传递的任意实参

  缺点:接口类型检查比较复杂。

  51、参数化类型经常为与其模板实参相关联的类型提供别名。

template<typename T>
class Vector{
    public:
    	using value_type = T;
    	// ...
};

  通过绑定某些或全部模板实参,就可以使用别名机制定义新的模板。

template<typename Key,typename Value>
class Map{
    	// ...
};
template<ttypename Value>
using String_map = Map<string,Value>;
String_map<int> m;// m是一个Map<string,Value>

猜你喜欢

转载自blog.csdn.net/YuYunTan/article/details/84591456