代码改变世界

侯捷C++八部曲:C++程序设计(Ⅱ)兼谈对象模型

2021-11-28 21:36  cascle  阅读(244)  评论(0编辑  收藏  举报

1. 导读

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 TL标准库主要是用模板泛型思维做出来的,而不是面向对象思维,多态基本没有,继承量不大(旧版本也是基本没有,新版本增多)

 

 

 

 

 

 

 

2. 转换函数 conversion function

 

 主要作用是把一个对象转为另一种数值的类型,以及另外一种类型被转过来

转出去:operator typename() const{},要转的类型就是typename作为函数名,编译器判断在需要这种typename的时候,自动调用Class::typename(this)函数。所以这个函数表明Fraction类可以被自动转为double。这个函数不需要写return type,转换不会改变对象的数据,所以要是const

转进来:下一节要讲的non-explict-one-argument ctor,通过构造函数把外面的对象创建为本类对象

编译器看到一个表达式,会做多种匹配,比如全局运算符匹配,类运算符匹配、构造本类对象、类型自动转换这些,会按一定顺序做匹配、调用,有和全局运算符冲突也不要紧

可以写多个类型转换函数

 

3. 无explict单参构造函数 non-explict-one-argument ctor

 

注意,单一参数不一定是一个参数,是说没有默认参数的就一个(argument和parameter不一样,一个实参一个形参) 

这样就可以将类外对象通过构造函数的调用转进来

注意,+的参数必须是常引用,因为临时对象不是常引用纵使改到了,也不会影响外面的对象,所以直接报错

转进来、转出去都是调用相应类的成员函数

 

 

 

 转进来、转出去都有的话,配合+运算符函数,报错

 

构造函数加explict:禁止编译器自己就调用构造函数进行类型转换

表达式操作数的顺序很重要,这里不会自动将f转为double了

 

 

这是一种代理模式

 

 4. 智能指针 pointer-like class

 

 箭头符号特殊行为:作用下去后会继续作用下去

智能指针:里边一定带着一个普通指针,移动要重载->和*这两个运算符

 

迭代器是另外一种智能指针,代表容器里的一个元素。这里支持的操作更多了

 

 

 核心就是操作符重载

智能指针主要重载了->和*这两个符号,++和--的迭代器之类的要重载

 

5. 仿函数 function-like class

为什么要一个类的对象像个函数?看后续课程

 

()是一个操作符,函数调用操作符

任何一个东西能接受小括号操作符,就把这个东西叫做函数或者一个仿函数

 

 

 

 

 

 为什么要继承这些只有typedef的父类?后面课程讲

这两个基类的大小都是 1,不是0

仿函数:一个类重载了()这个符号

 

6. namespace经验谈

把代码包起来,防止名称冲突

 

 

7. 类模板 class template

 

 抽出来允许使用者指定的类型,放到T上

 

8. 函数模板 function template

 

函数模板可以自动推导,从参数到声明看,参数是什么,声明就是什么,参数有T、声明就有T,格式自然就要这么写了

声明里的T,是应用于参数类型上

模板会被编译两次,第一次参数代替生成实体类、函数,第二次应用生成的实体进行编译

 

9. 成员模板 member template

 

属于模板里的一个member,本身又是一个模板,类型由其参数自动推导

外面的T1、T2模板参数是 允许变化的,一旦T1和T2确定了,里面的U1和U2又可以变化,根据不同参数推导出来,生成不同函数体(函数模板参数自动推导,不需要指定)

标准库的很多构造函数会被设置成成员模板

 

 

 可以看到,成员模板的那个构造函数,参数p自动带入了U1、U2的类型。函数模板可以自动推导,推导由参数那行的U1、U2到声明里的蓝色的U1、U2

把另外一种pair的对象赋值给本对象,那个pair对象的模板参数不必和本对象类型的一样,只要能兼容就好

p一定带模板参数,直接就推导出来U1、U2了

pair本来就要求由两个参数,所以写的时候相当于用它,要带U1、U2,相应的声明就要带U1、U2对应其类声明的T1、T2,所以写法上这样写

归根到底,成员模板是由其参数是个模板类或者函数(这个参数当然可以变,什么类型都行),带来实际模板参数,U1、U2定了其声明就定了,又带到了其template行声明参数里

成员模板的参数p有类型,这个类型恰好是个模板类型(该类型已确定),就定了成员模板声明怎么写,要用到哪些声明类型

这样模板成员更有弹性

 

 

类 自己可以有任意的参数传进来,构造函数允许传进来的是个模板类的对象

 

10. 模板特化 specialization

 

特化的反面是泛化,泛化就是模板

模板特化是指 ,一个模板类,针对特定类型参数的类,实现独特的设计,同样函数与通用泛化实现方式不一样

特化写法:模板声明里没参数,类名后面直接加“<参数>”

使用的收类名就是特化后的名称,要带尖括号

特化优先级高于泛化,编译器找到特化类就用不自动生成了

 

11. 模板偏特化 partial specialization

 两个角度的偏:个数上的偏和范围上的偏

个数上的偏:模板参数确定一部分,语法上体现,还有template声明,但是参数一部分确定。不能跳着来

 

范围上的偏:将类型缩小到某一范围,比如到某种指针类型

这里如果实参是某个类型的指针,就用这套代码

 

不管哪个偏,使用时候的实参要用到对应声明里的某个类型,但是又会加一些东西,比如<bool,Alloc>,<String*>,都是有声明里的东西

实际用的实参里带的东西,匹配哪些上了特化、偏特化的东西,就用匹配到的

特化、偏特化的东西和泛化的东西完全是两个东西

偏特化的优先级高于泛化

 

12. 模板模板参数 template tempalte parameter

 模板类作为模板参数,第一个T的实际参数带入第二个参数(也就是黄色的模板类)生成一个实体类

模板类Container拿第一个模板参数做自己的模板参数

类里边用的时候,用Container<T>指代(参数只是一个Container)

外边的时候用模板类名,如果参数就一个直接把Container填进去;如果带两个参数只不过一个可以省略,这里编译器无法识别,所以要用using来指定Lst,见后面课程

模板模板参数更有弹性

 

 

 

 

 这种不算模板参数,不带template声明,list<int>已经不是模板了,已经绑定了

 所以参数要是模板未定义类型才叫模板模板参数

 

13. 关于C++标准库

除了经典算法,算法里还包含要求高效率实现的代码小片段

 

 

 参考网址: https://cpprocks.com/c1114-compiler-and-library-shootout/

C++11 language features support

FeatureVS Nov 2013 CTPVS2013Intel 14.0
auto Yes Yes Yes
decltype Yes Yes Yes
Lambda expressions Yes Yes Yes
nullptr Yes Yes Yes
static_assert Yes Yes Yes
Range based for loop Yes Yes Yes
Trailing return type in functions Yes Yes Yes
extern templates Yes Yes Yes
>> for nested templates Yes Yes Yes
Local and unnamed types as template arguments Yes Yes Yes
Variadic macros Yes Yes Yes
Variadic templates Yes Yes Yes
Default template arguments in function templates Yes Yes Yes
final method keyword Yes Yes Yes
override method keyword Yes Yes Yes
Strongly typed enums Yes Yes Yes
Forward declared enums Yes Yes Yes
Explicit type conversion operators Yes Yes Yes
Raw string literals Yes Yes Yes
Delegating constructors Yes Yes Yes
Template aliases Yes Yes Yes
Non-static data member initializers Yes Yes Yes
Deleted methods Yes Yes Yes
Initializer lists Yes Partial Yes
Rvalue references and move semantics Yes Partial Yes
Defaulted methods Yes Partial Yes
C99 compatibility Partial Partial Yes
New built-in types Partial Partial Partial
Member function ref qualifiers Yes No Yes
noexcept Partial No Yes
constexpr Partial No Yes
Alignment support Yes Partial No
Magic statics Yes No Partial
Thread local storage Partial Partial No
Generalized attributes No No Yes
Inline namespaces No No Yes
sizeof on non-static data members without an instance Yes No No
Encoding support in literals No No Yes
Arbitrary expressions in template deduction contexts No No Yes
Inheriting constructors Yes No No
Changed restrictions on union members No No Partial
User defined literals No No No

C++14 language features support

FeatureClang 3.4GCC 4.9VS Nov 2013 CTPIntel 14.0
Return type deduction for regular functions Yes Yes Yes No
Binary literals Yes Yes No Yes
Generic lambdas Yes Yes Partial No
Tweaked wording for contextual conversions Yes Yes No No
Runtime sized arrays with automatic storage duration Yes Yes No No
Initialized lambda captures Yes Yes No No
[[deprecated]] attribute Yes Yes No No
Single quotation mark as digit separator Yes Yes No No
C++ sized deallocation Yes Yes No No
Variable templates Yes No No No
Relaxed requirements on constexpr functions Yes No No No
Member initializers and aggregates Yes No No No
Avoiding/fusing memory allocations Yes N/A No No

C++14 library features support

Featurelibc++libstdc++VS Nov 2013 CTP
make_unique Yes Yes Yes
Improved operator functors Yes Yes Yes
Additional template aliases for transformation type traits Yes Yes Yes
Fixing constexpr member functions without const Yes Yes No
exchange() utility function Yes Yes No
Retrieving tuple elements by type Yes Yes No
std::result_of and SFINAE Yes Yes No
Improvements to integral_constant Yes Yes No
User-defined literals for standard library types Yes Yes No
More robust non-modifying sequence operations Yes Yes No
Quoted string I/O manipulator Yes Yes No
constexpr library additions: chrono Yes Yes No
constexpr library additions: containers Yes Yes No
constexpr library additions: utilities Yes Yes No
constexpr library additions: complex Yes No No
constexpr library additions: functional Yes No No
Compile-time integer sequences Yes Yes No
Shared locking Yes Yes No
Heterogeneous comparison lookup in associative containers Yes No No
Null forward iterators Yes No No
Sized deallocation No No No
Consistent metafunction aliases No No No
Discouraging rand() in C++14 No No No

https://en.cppreference.com/w/cpp/compiler_support,这个网址更多,每隔3年C++就更新一次标准,慢慢学吧

 

 

 

 

 

 

14. 三个主题

数量不定的模板参数 variadic templates

 

 用的时候args...解包,...就是一个包,在不同地方有不同含义

调用一个这样的函数,会不停的递归,要额外定义一个参数为空的函数

一个和一包,除了用来函数递归,还可以用在类组合、类继承,看后面课程

 

auto

 

 auto不能断行

 

range-base for

 

 新的for循环格式,冒号右边必须是个容器

{}自然而然成为一个容器

以前是foreach仿函数和迭代器遍历

 

15. 引用 Reference

 

 引用要有初始值,之后不能再代表其他对象了

reference是一种代表关系

 

 

 

 

 reference是一种漂亮的pointer

小括号和大括号之间的const算是函数签名的一部分,修饰参数不算

 

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

 

 面向对象:谈的是class和class之间的关系

红色部分编译器自动调用

 

 

 

 

17. vptr和vtbl

 

 

 vptr也是继承父类的,只不过里面的数值可能不同

父类有虚函数,子类一定也有。函数继承的是调用权,父类能调用的虚函数子类也要能调用

虚表也要继承,里边的数值可以替换

子类virtual可加可不加,但是为了清晰要加

动态绑定:代码写成依赖一段内存的数值去调用相应函数,这段内存里的数值或者指向的内存地址可以动态改写

静态绑定:代码直接依赖一段静态数值

 

 

 对比C的优势,有了变化增加了新类,C++加一个新类就好,C还要改其他地方的代码

根本原因是把静态代码变成动态代码,改了结构

函数调用包含两种:

1.静态

2.动态,通过引用、指针调用虚函数,又叫做虚机制。看p指向什么来决定,所以叫动态绑定。也叫作多态,同样类型的指针可以指向不同子类型的东西

 

18. 关于this

 

 this pointer:对象地址

this是个关键字也是种观念

this作为成员函数默认的第一个参数

上图参考模板方法

 

19. 关于Dynamic Binding