【侯捷】C++面向对象高级编程(下)
一、导读
目标:
书籍推荐:
二、转换函数
2.1 conversion function,转换函数
示例:Fraction
转换为 double
double
函数不可以有参数;没有返回类型;- 函数名称一定是
operator type()
; - 只要合理,一个类可以设计多个转换函数。
编译器在编译上面的代码时,在处理这行代码:
double d = 4 + f;
的时候,会先查看是否有写函数Fraction operator+(double, Fraction&)
,目前的代码中没有这个函数,于是编译器就另寻他路,看是否能将 f
转换为 double
,就会到代码中查看是否设计了转换函数,然后就发现了operator double()
这个转换函数。于是编译器就将f
转换为 3/5=0.63/5 = 0.63/5=0.6,所以最终的结果 d=4.6d = 4.6d=4.6。
正确的代码应该如下:
/*************************************************************************> File Name: 001.Fraction_to_double.cpp> Author: Maureen > Mail: Maureen@qq.com > Created Time: 三 11/17 23:52:46 2021************************************************************************/#include <iostream>
using namespace std;class Fraction
{public:Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den) {}operator double() const {cout << "double function is called" << endl;return ((double)m_numerator / m_denominator);}
private:int m_numerator;int m_denominator;
};int main(){Fraction f(3, 5);double d = 4 + f;cout << "f = " << f << endl; //0.6cout << "d = " << d << endl; //4.6return 0;
}
标准库中的应用:
reference operator[]
函数要返回一个 bool
值,则 reference
类型中一定有个转换函数将结果转换为bool
值类型,果然,在__bit_reference
中有个转换函数 operator bool() const
。
2.2 non-explicit-one-argument ctor
此处的one-argument
是指至少有一个实参,若有多个实参也可以。
示例:将double
转换为Fraction
2.3 conversion function vs. non-explicit-one-argument ctor
绿色的部分可以将 4 转换为 Fraction
,黄色部分可以将 f
转换为 double
。这两条路径都可行,产生了歧义,所以编译器不知道应该选择哪个路径。
2.4 explicit-one-argument ctor
explicit
关键字的意思是告诉编译器,不要将 4 自动转换为 4/1
。
此处的+
要将4
转换为 Fraction
类型,但是因为构造函数加了 explicit
关键字,所以 4 无法转换为 Fraction
,因此出现错误。
百分之九十的情况,explicit
关键字出现在构造函数前。
三、智能指针
3.1 pointer-like classes,关于智能指针
将一个 class
设计出来像一个指针或者函数。
sp->method()
这行代码,->
作用于sp
,即调用了T * operator->()
函数,得到了px
,而->
得到的结果如果要继续执行下去就要继续调用->
,这是 C++ 中->
的特性;- 智能指针类中一定有指针类型的变量,且一定要写操作符
*
和->
的函数,写法一般都是如上所示。
3.2 pointer-like classes,关于迭代器
标准库中的链表:
- 迭代器也是智能指针,但是相比较于
shared_ptr
中的操作符重载的写法,有所变化; - 迭代器不仅要实现操作符
*
和->
,还要实现其他的操作符。
四、仿函数
4.1 function-class classes,所谓仿函数
设计一个class,让它像一个函数。
4.2 标准库中的仿函数的奇特模样
4.3 标准库中,仿函数所使用的奇特的 base classes
五、namespace经验谈
六、模板
6.1 class template,类模板
- 类模板使用的时候需要指定类型
6.2 function template,函数模板
- 此处的
template <class T>
中的class
,可以修改为typename
; - 使用函数模板的时候不需要指定类型;
- 模板会编译一次,实际使用的时候会再编译一次;
6.3 member template,成员模板
问:把一个由鲫鱼和麻雀构成的 pairt
,放进(拷贝到)一个由鱼类和鸟类构成的 pair
中,可以吗?
答:可以。
问:反之,可以吗?
答:不可以。
6.4 specialization,模板特化
6.5 partial specialization,模板偏特化—— 个数的偏
6.6 partial specialization,模板偏特化—— 范围的偏
- 所谓的”范围的偏“,指的是之前的泛化版本是任意类型,而偏特化版本是指针类型;
C<string> obj1;
使用的是泛化版本;C<string*> obj2;
使用的是偏特化版本,因为是指针类型。
6.7 template template parameter,模板模板参数
- 容器中的类型未定,容器本身就是个模板;
- 容器还有其他模板参数,平时没有写是因为有默认值;
- 此处的两个×不是模板模板参数有错,而是智能指针
unique_ptr
和weak_ptr
的特性导致此处的错误。
这不是 template template parameter
- 使用第二模板参数的时候,必须写成
list<int>
,因为已经绑定了int
,不再是模糊的,所以它不是模板模板参数。
七、关于C++标准库
八、更多细节深入
九、C++2.0
9.1 了解你的编译器对C++2.0的支持度
9.2 确认支持C++11:marco __cplusplus
/*************************************************************************> File Name: test.cpp> Author: Maureen> Mail: Maureen@qq.com> Created Time: 一 11/22 16:23:29 2021************************************************************************/#include <iostream>
using namespace std;int main() {cout << __cplusplus << endl; //201103return 0;
}
9.3 三大主题
9.3.1 variadic templates(since C++11)
数量不定的模板参数
sizeof...(args)
可以获得pack
里的参数个数。
完整代码:
/*************************************************************************> File Name: 02.variadic_templates.cpp> Author: Maureen > Mail: Maureen@qq.com > Created Time: 一 11/22 16:36:59 2021************************************************************************/#include <iostream>
using namespace std;void print() { }template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args) {//cout << "pack numbers: " << sizeof...(args) << endl;cout << firstArg << endl;print(args...);
}int main() {print(7.5, "hello", bitset<16>(377), 42);return 0;
}
9.3.2 auto(since C++11)
auto ite;
没有赋值的时候,编译器是无法推导出 ite
的类型的,所以使用错误。
9.3.3 ranged-base for (since C++11)
如果要改变原来的值就使用引用。
9.4 reference
- reference一定要设初值,说明它代表什么东西;自此之后,reference就不能代表其它了;
- reference底层有个指针指向它所代表的东西;
示例:
9.5 reference的常见用途
- 引用的底层是用指针实现的,所以当传的数据很大的时候,通过引用传递速度更快;
- 签名不包含 return type。
十、object model
回顾:
- Composition(复合)关系下的构造和析构
- Inheritance(继承)关系下的构造和析构
- Inheritance+Composition关系下的析构和构造
10.1 对象模型(Object Model):关于 vptr 和 vtbl
虚指针和虚表。
- 子类中有父类的成分;子类不仅会继承父类的数据,还会继承函数的调用权利;
- 如果类中有虚函数,类就会多一个指针的大小,即虚指针;
- 不管类中有多少个虚函数,都只有一个虚指针
vptr
,指向虚函数表vtbl
;vtbl
中放置的是函数指针; - 如果父类有虚函数,子类也一定有虚函数;
B
继承了A
,所以B
继承了A
的虚函数,B
中也有两个虚函数vfunc1
和vfunc2
,只是B
又重写了方法vfunc1
;- “从
p
到ptr
到vtbl
到 某个方法的流程” 编译器解析出来就是(*(p->vptr)[n])(p);
或者(* p->vptr[n])(p);
- 为了放置不同大小的形状,所以要放入指针,指向父类;
- 希望做到:遍历容器,调用每个指针所指向的
draw
;所以draw
必须是虚函数,才能实现这种功能; - 虚函数的这种用法叫做多态(polymorphism);
总结:C++编译器处理函数调用的时候,要考虑是静态绑定还是动态绑定。
- 静态绑定被编译成
call xxx
,其中的xxx
是函数地址; - 如果符合以下三个条件就会进行动态绑定:① 必须通过指针调用;②指针是向上转型的
up-cast
;③调用的是虚函数。编译器会将其编译成(*(p->vptr)[n])(p);
或者(* p->vptr[n])(p);
,具体调用的是哪个函数要看p
指向的是什么。
多态、虚函数和动态绑定其实都是一回事。
10.2 对象模型(Object Model):关于 this
通过某个对象调用函数,则该对象的地址就是
this
;上述的是模板方法(Template Method);
this->Serialize();
函数满足动态绑定的三个条件,所以编译器会进行动态绑定;
10.3 对象模型(Object Model):关于Dynamic Binding
- 此处的
a.vfunc1()
,通过对象调用函数,所以是静态绑定;
- 此处的虚函数调用,满足动态绑定过的三个条件,是动态绑定。
十一、谈谈const
const
只能放在成员函数的后面,不能放在全局函数的后面;const
修饰成员函数是为了告诉编译器这个成员函数不打算修改类中的成员数据的意图,请编译器帮忙把关是否违反了这个意图。
const
属于签名;- 如果涉及到引用,可能就会有共享,为了防止被修改,就要拷贝一份进行修改,即涉及到共享,就要考虑
Copy On Write
; - 常量字符串不必考虑
Copy On Write
;
十二、关于new,delete
12.1 回顾
- 类中的
new
和delete
都可以进行重载,可用于内存池的设计;
12.2 重载::operator new, ::opeartor delete, ::operator new[], ::operator delete[]
12.3 重载member operator new/delete
- 重载的函数会接管
new
/delete
分解后的步骤中的相同函数名的函数
12.4 重载member operator new[]/delete[]
12.5 示例
说明:
Foo* pf = new Foo;
delete pf;
如果没有重载运算符new
和delete
的成员函数,就调用全局的operator new
;
Foo* pf = ::new Foo;
::delete pf;
无论是否有重载运算符new
和delete
的成员函数,都调用全局的operator new
。
Foo with virtual dtor
的size
比Foo without virtual dtor
的size
大 4 的原因是,类中如果有虚函数,就会多一个虚指针,在32bit机器上占 4 个字节;Foo* pArray = new Foo[5]
的大小为 64, 其中多出来的 4 是计数counter,表示有5个元素,将 “array 的整包大小 + 一个计数的counter” 进行分配;
- 无论是否调用的是重载的
new
和delete
函数,在数组的前面加一个 counter 的逻辑是不会变的
12.6 重载 new(), delete()
12.7 basic_string 使用 new(extra) 扩充申请量
标准库中 placement new
的例子:
【侯捷】C++面向对象高级编程(下)相关推荐
- 【C++】侯捷C++面向对象高级编程(下)
转换函数(conversion function) 可以把"这种"东西,转化为"别种"东西. 即Fraction --> double class Fra ...
- 【C++】侯捷C++面向对象高级编程(上)
C++面向对象高级编程 前言 C++ Programs代码基本形式 文件类型 头文件写法 头文件布局 class1--complex 类的声明 inline--内联函数 class访问级别(acces ...
- 一、C++面向对象高级编程(下) (侯捷)
侯捷 C++八部曲笔记汇总 - - - 持续更新 ! ! ! 一.C++ 面向对象高级开发 1.C++面向对象高级编程(上) 2.C++面向对象高级编程(下) 二.STL 标准库和泛型编程 1.分配器 ...
- 侯捷-C++面向对象高级开发(操作符重载与临时对象)
侯捷-C++面向对象高级开发(操作符重载与临时对象) 1.操作符重载与临时对象 任何成员函数有一个隐藏的this pointer指向,指向调用者. 传递者无需知道接收者是以什么形式接收 就比如下面方框 ...
- 侯捷-C++面向对象高级开发(头文件与类的声明,构造函数,参数传递与返回值)
侯捷-C++面向对象高级开发 1.头文件与类的声明 Object Based:面对的是单一的class的设计 Object Oriented:面对的是多重classes的设计,classes和clas ...
- 侯捷-C++面向对象高级开发(三大函数:拷贝构造,拷贝赋值,析构)
侯捷-C++面向对象高级开发(三大函数:拷贝构造,拷贝赋值,析构) 三大函数:拷贝构造,拷贝赋值,析构 第一个是拷贝构造,第二个是拷贝赋值 编译器有一套默认的东西实现这俩东西,可用到complex的实 ...
- 侯捷 C++面向对象高级开发(下)笔记整理
C++面向对象高级开发(下) 一.导读 (1)泛型编程和面向对象编程分属不同的思维, (2)由继承关系所形成的对象模型,包含this指针,vptr指针,vtbl虚表,虚机制,以及虚函数造成的多态. 二 ...
- 侯捷C++学习记录-面向对象高级编程下
本章谈到三大函数.stack堆.heap栈和内存管理. new 操作 与 delete 操作,最后对String类实现进行复习. 学习static 关键字及类模板涉及到的设计模式有:单例模式.Adap ...
- 一、C++面向对象高级编程(上) (侯捷)
侯捷 C++八部曲笔记汇总 - - - 持续更新 ! ! ! 一.C++ 面向对象高级开发 1.C++面向对象高级编程(上) 2.C++面向对象高级编程(下) 二.STL 标准库和泛型编程 1.分配器 ...
- 侯捷C++课程笔记02: 面向对象高级编程(下)
本笔记根据侯捷老师的课程整理而来:C++面向对象高级编程(下) pdf版本笔记的下载地址: 笔记02_面向对象高级编程(下),排版更美观一点(访问密码:3834) 侯捷C++课程笔记02: 面向对象高 ...
最新文章
- python数据库安装教程_python MySQLdb Windows下安装教程及问题解决方法
- 量子计算何时具有真正的商业价值?
- RedisTemplate实现事物问题剖析和解决
- pandas.read_csv——分块读取大文件
- 华为手机销量超过苹果,华为能算是全球第二大手机厂家吗?
- 北京达内python价格_记录在北京达内学Python-day07
- HDOJ 2074 叠筐
- 【前端 · 面试 】JavaScript 之你不一定会的基础题(二)
- python教材答案字典与集合_Python——集合与字典练习
- 微信小程序登录,后端如何处理?
- SECS\GEM RMS系统简介
- courant数_CFD中常用的参数介绍 | 坐倚北风
- 脱离低级趣味- Python ‘\r‘, ‘\n‘, ‘\r\n‘ 的彻底理解
- 逐飞与龙邱英飞凌miniwiggler仿真器硬件接口适配与差异总结
- 东西方赌王“口水战”升级 措词激烈论“竞争”
- asterisk简单实用
- 实现单点登录(伪登录)
- 如何用css实现带√三角形
- 【PHP】高端响应式自适应房屋出售建筑设计企业织梦模板
- 图像的线性分类器(感知机、SVM、Softmax)
热门文章
- hdoj4826Labyrinth【dp】
- 网络技术故障背后:50元发动的DDoS流量攻击
- 网易的java微专业_网易微专业Java开发工程师(Web方向)
- html入门、结构、标签、列表、表格
- How to install php evn on ubuntu
- X11 - X client数量达到上限并报错Maximum number of clients reachedxlsclients
- 超简单的QFN封装芯片的手工焊接方法,先收藏
- html粘性菜单,导航菜单:jQuery粘性滚动导航栏效果
- Android Protect-0.重新打包和签名
- 小熊派使SPI驱动TFT-LCD(ST7789)显示试验