目标

image-20220117143513546

转换函数

定义

image-20220117144200362

黄色特性:fraction可以被转换为double,按照return返回

这种就是转换函数,没有函数类型

通常要加上const

注意:这里return double转换有问题,需要改成return (double)f_up / (double)f_down;

只要认为合理,可以设置任何operator

non-explicit-one-argument ctor

image-20220118160821235

可以把别的东西转化为fraction

转换函数与non-explicit-one-argument ctor

image-20220118161014414

编译器发现两条路可行,所以报错

explicit-one-argument ctor

image-20220118161349464

加上explict只有用在这里,在构造函数前面

告诉编译器不要自动转化为fraction

转换函数的其他用途

image-20220118161705257

pointer-like classes

关于智能指针

image-20220118162214588

指针所做的,智能指针应该都要做到

在这里关注* 和->

share在接受普通指针

右下角->在把sp转化为px已经消耗掉了啊?

箭头符号在作用一个以后,还能再作用下去

关于迭代器

image-20220118162857699

主要遍历容器,所以要写++和–

链表:

image-20220118163133904

链表迭代器node必然有一个指针

对迭代器解指针拿的是数据,所以直接return数据data

function-like classes 所谓仿函数

为什么要让class像函数?

定义

image-20220118192957126

函数是接受一个()符号,所以class可以通过重载()就可以作为函数

奇特模样

image-20220118193812537

image-20220118193826727

上面都继承了如下:

image-20220118193901727

仿函数都会继承一些奇特的base classes

标准库里都会有很多class使用仿函数

namespace经验谈

image-20220118194250852

可以把函数放在namespace里,这样就不用重复的取名字了

相当于分组一样

模板

class template

image-20220118194643071

function template

image-20220119151321045

函数模板在使用时自动推导类型

member template

image-20220119162106328

image-20220119162430881

当然可以,但是反之不可以

image-20220120152847953

specialization 模板特化

作为一个设计者可能面对独特的类型

image-20220121201154454

画两条线,在电脑上必然是实数

第一个框框是泛化

指定特别的类型,char或者int等等,编译器就会用特定的算法

浅绿色是临时对象,蓝色就是参数

模板偏特化

个数上的偏

image-20220121201804069

范围上的偏

image-20220121203838551

可以把范围限制在指针

模板模板参数

typename和class只有在模板这个位置共通

image-20220121204318887

用在 传一个容器,容器的指定类型,就需要模板模板参数

为什么第一个错了,因为list不只有一个参数,所以不可以这么用,要引入第二个框的两个语法

关于c++标准库

image-20220123100333497

都用一遍

三个主题

variadic templates(c11) 数量不定的模板参数

image-20220123102551176

print(args…)一直在递归

最后变成0个的时候调用上面的void print()

#include <iostream>
#include <bitset>
using namespace std;
void print()
{}
template <typename T,typename... Types>
void print(const T& firstArg, const Types&... args)
{
    cout << firstArg << endl;
    print(args...);
}

int main() {
    print(7.5, "hello", "word", bitset<16>(377));
}

sizeof...(args)可以知道args的大小

auto (c11)

image-20220123104421938

编译器知道find的返回类型,就会自动补上

ranged-base for (c11)

image-20220123105000775

reference

image-20220124094849653

习惯*靠向int,point to int

image-20220124095557893

常见用途:

image-20220124095815686

声明:<类型标志符>函数名(参数表)const;

说明:

(1)const是函数类型的一部分,在实现部分也要带该关键字。

(2)const关键字可以用于对重载函数的区分。

(3)常成员函数不能更新类的成员变量,也不能调用该类中没有用const修饰的成员函数,只能调用常成员函数。

(4)非常量对象也可以调用常成员函数,但是如果有重载的非常成员函数则会调用非常成员函数。

复合&继承关系下的构造和析构

继承关系下的构造和析构

image-20220124101108226

哺乳动物-猪

先创建哺乳动物再创建猪,先删除猪再删除哺乳动物

复合关系下的构造和析构

image-20220124101048832

继承和复合关系下的构造和析构

image-20220124101621169

对象模型

关于vptr虚指针和vtbl虚表

重要

image-20220124143019847

当一个类有一个虚函数的时候,虚函数是最重要的一部分,如果只谈继承不说虚函数用途不,只要类里面有一个虚函数,对象里面就会多一个指针(一万个虚函数也是一个指针)。

继承函数是继承调用权

B改写了一个虚函数,C又改写了B的虚函数

a、b和c里面的指针指向了一个虚表,虚表中包含了数个指向虚函数的指针

不再是单纯的静态调用,而是动态调用,面向对象很重要的环节!

image-20220127090429443

image-20220127090459935

为了让容器放各种的形状,就要指定容器里放各类的指针,draw函数要经常改写以适应各类形状

符合以下三个条件做动态绑定

1.通过指针绑定

2.指针向上转型,up-cast

3.调用虚函数

只要符合三个条件,编译器就编译成image-20220127090429443

右下角成为多态

关于this

image-20220127091650019

虚函数两个用法,一个是上一节的,一个是这节的

关于 Dynamic Binding

image-20220127093014265

image-20220127093219732

补充

关于const

放在成员函数后面的const是很容易被忽略的,

image-20220127093849043

意图是:修饰成员函数,加const至关重要

关于new,delete

image-20220127141230112

class可以重载new和delete

重载::operator new,operator delete,::operator new[],::operator delete[]

image-20220127141456565

重载这些影响非常广

member operator new/delete

image-20220127141635126

通常接管做内存池

重载 member operator new[]/delete[]

image-20220127141911896

实例,接口

image-20220127142023461

如果使用者想要绕过特性,使用::new

image-20220127142203550

12×5是60,结果是64,多出来的4记录了数组大小(计数器)

image-20220127142708033

重载new(),delete()

image-20220127142834729

image-20220127142932222

image-20220127143306892

对象构造的时候要分配内存然后调用构造函数,构造函数发出异常没成功,就要把分配的内存释放掉,对应的delete就被调用起来

basic_string 使用 new(extra) 扩充申请量

标准库:

image-20220127143909296

当create自己的时候,分配一个rep+extra内容空间,rep做的是计数器。