侯捷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
Feature | VS Nov 2013 CTP | VS2013 | Intel 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
Feature | Clang 3.4 | GCC 4.9 | VS Nov 2013 CTP | Intel 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
Feature | libc++ | 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