侯捷C++面向对象高级开发(下)笔记

concersion function(转换函数)

举个例子:分数转换成小数

operator开头, 后接上想转换的类型,无参数,返回类型不用写,因为已经有目标转换类型了,防止出错。
转换不会改变对象属性值,故建议加上const。

对于

Fraction f(3,5);
double d = 4 + f;

编译器首先会找一个全局函数,operator+,第一个参数是int/double(int可以转换成double),第二个参数是fraction,但是没有这样的函数,

所以会试着把f转换成double,去找转换函数。

non-explicit-one-argument constructor

对于

Fraction f(3,5);
Fraction d2=f+4;

对于f在其类内找到了对应的operator+,但是右边的参数得是Fraction,这里是4,编译器会试着将4转换成Fraction,由于有绿色那一块的构造函数,故4可以转换成Fraction(4,1),然后就可以进行计算,这就是隐式转换。

同时有绿色和黄色代码时,对于下面这段代码编译器会报错

Fraction f(3,5);
Fraction d2=f+4;

因为会有二义性,既可以把f转换成double进行计算,也可以把4转换成Fraction进行计算

explicit-one-argument constructor

基本只有构造函数会用到,模板很细微的地方也会用到

对于

Fraction f(3,5);
Fraction d2=f+4;

不能将4隐式转换成Fraction,加法失败,或者将f转换成double,最后由double来赋值(其实也是将double隐式转换成Fraction,但也不被允许),故最终报错

pointer-like classes

智能指针

指针能做的,智能指针都要能做

对于operator*很简单,返回类内指针指向的对象即可,*px

对于operator->,直接返回px,对于sp->method();会将sp->转换成px,那么不就变成pxmethod();了吗?不会,箭头符号会持续作用下去,不会被消耗掉,最终px->method();就显得合理了

迭代器

迭代器可以看成另外一种智能指针,迭代器需要代表容器中的一个元素,可以当做智能指针,但是它不但要处理*和->,还要处理== != ++ --等符号

下面这个例子是用双向链表实现迭代器

function-like classes(仿函数)

如何让一个类像一个函数呢

如果一个东西能够接受()操作符,我们就把这个东西叫做函数或者说像函数的东西

标准库中的仿函数都会继承一种奇特的base class

namespace经验谈

用不同名字的namespace把函数、变量等包起来,防止重名起冲突

Template 模板

class template(类模板)

用T来泛指类型,使用时再具体指明是什么类型

function template(函数模板)

函数模板使用时不必指明具体类型,编译器会进行实参推导,得出传入参数是什么类型

Member Template(成员模板)

在构造pair时,允许使用U1、U2来构造,但是需要T1能够通过U1来构造,T2能够通过U2来构造,否则会报错,故图中例子可行,如果反过来用D2、D1来构造B1、B2就不行,D2不能用来构造T1,D2只继承了B2而没有继承B1故会报错

specialization模板特化

就是在泛化基础上对某些独特的类型,要做独特的设计

下面的例子表示hash可以接受很多类,但是对于char、int、long有自己独特的设计

对于cout<<hash<long>()(1000);

它表示创建了一个临时变量hash<long>(),它调用了重载的()函数,会使用特化中的代码而不是泛化中的

partial specialization 模板偏特化 -- 个数的偏

两个typename,只特化(绑定)其中一个,第二个参数还是泛化

不能跳跃绑定,只能从左到右一个一个特化

partial specialization 模板偏特化 -- 范围的偏

特化指针类型,当类型是指针时使用特化的代码

template template parameter 模板模板参数

假如需要模板传入一个模板就需要用到模板模板参数

当我们声明一个模板模板参数时,我们需要使用 template <class T>,而不是 template <typename T>。这是因为在模板模板参数中,我们需要明确指定参数是一个类模板,而不是一个单独的类型。

尖括号内typename和class相同

Container使用了typename T来当做自己模板的实际值,像例子中就表示list是一个模板,其中装的是前一个参数string,但是这样有问题,容器有第二模板参数,甚至有三、四,平时不写是因为有默认值,但是这里这样用语法过不了。

为了解决这个问题可以用Lst那一行(c++2.0语法)

有的智能指针只接受一个模板参数,所以可以这么写,打×不是参数原因,是指针特性原因

在使用中传入的参数已经不是模板了,所以这个不是模板模板参数

variadic templates(since C++11)数量不定的模板参数

...表示多个参数,递归调用自己,不断打印出来第一个参数

auto(since C++11)

让编译器自己推断是什么类型

ranged-base for(since C++11)

auto elem 是值传递,会把值拷贝到elem中,如果想要更改vec中的内容,传入引用。

Reference

引用必须初始化

引用就是别名,实际上用指针来实现,真实大小为指针的大小,但是sizeof(r)==sizeof(x),&r==&x,这是编译器制造的假象

引用不能重新再代表别的对象

const是函数签名的一部分

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

复合:一个类中含有别的类。

构造由内而外构造,析构由外而内析构(父子类继承也一样)

vptr和vtbl(虚指针和虚表)

继承函数继承的是函数的调用权

每个对象都有一个虚指针(存储在类对象开头的4个字节),指向自己所属类的虚表(虚表是同一个类的对象共用的)

虚表中存放了虚函数的地址

子类重写父类虚函数会改变子类虚表中该函数的地址

通过指针对象中找到虚指针,再找到虚表,再找到对应的虚函数(作用之一是当父类指针指向子类,要删除基类指针时,调用的仍然是子类的析构函数,就不会导致内存泄漏),这是动态绑定

而静态绑定是直接使用call函数地址。

用父类指针指向子类,调用draw函数,执行的还是子类的draw函数

符合动态绑定的条件

1.通过指针调用

2.指针向上转型(this指向子类)

3.调用虚函数

this指针

对象的地址就是this

通过对象来调用函数,实际上是将自己的地址传入函数,就是this指针(所有的成员函数都会有隐藏的this指针作为参数)

这个例子中myDoc是子类对象,想要调用OnFileOpen函数,由于子类中没有这样的函数,故会调用父类的函数(感觉是静态绑定,直接call这个函数的地址),并且将自己的地址传入该函数(也就是this)后续其他函数调用都是以this->的形式,而执行到Serialize()时(由于它是虚函数且子类中有重写),就会走虚指针、虚表那一套流程调用子类中重写的Serialize()

关于Dynamic Binding 动态绑定

a.vfun();是对象直接调用,不符合动态绑定条件,调用A类的函数

从call往前的几行汇编 用C表现是(*(p->vptr)[n])(p);

即通过p指针找到vptr,再找到虚表的第n个,再用函数指针的形式调用,传进去的p即为this pointer。

补充

const修饰函数一般是修饰成员函数。

成员函数的const 和 non-const 版本同时存在时

const 对象只能调用const版本

non-const 对象只能调用non-const版本

不同时存在时,non-const 对象无论哪种都能调用,但const 对象只能调用 const版本

new和delete重载

全局重载

类内重载

示例:

如果使用::new就会使用全局的new,不执行自己的重载

delete[]和new[]

本来5个对象应该是60,但是数组中多了一个记录元素个数的数据,所以是64

placement new/delete

对于Foo* pf = new(300,'c') Foo;总共有3个参数,有一个size_t自动传入

只有构造函数发出异常时才会执行对应的delete

编译器不同结果也不同,可能会调用也可能不会

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

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值