面向对象编程下—兼谈对象模型
转换函数
Fraction转换为double,没有return type:
将fraction转换为double4
3=3/1;所以第二个参数可以默认为1;
one-argument 一个参数就可以了;
上面代码考虑将4转换为Fraction。
当有两条路可行之时,会发生歧义二义性;
explicit
明白的,明确的,不可以将3变为3/1,
用在构造函数前面,
标准库中转换函数的利用
代理,a代表B,一定有一个函数将a转换为b;
pointer-like clasa
shared_ptr
操作符重载(*)和(->)
迭代器的操作符重载
链表的迭代器
function-like classess (仿函数)
select1st<pair()()>
仿函数继承来自unary_dunction和binary_function;
空类,理论上为0,上面的类实际大小为1;
namespace经验
把一些东西区隔开来;防止类名和函数名冲突;可以用namespace包装起来;
class template(模板)
function template(函数模板)
编译器·会对函数模板进行实参推导;
member template (成员模板)
T1|T2:鲫鱼、麻雀;
为了让构造函数更加有弹性;
聪明指针指向鱼类
//new 一个鲫鱼,指针向上移动可行的;
Base *ptr=new Derived1;//up-cast
specialization模板特化
偏特化
绑定其中一个;个数上的偏
范围上的偏
任意的范围----->指针
模板模板参数
下面不是模板模板参数。因为list已经指出了int类型;
数量不定的模板参数
template<typename T,typename ...Types>
void print(const T&firstArg,const Types& ..args){
cout<<firstArg<<endl;
print(args...);
}
auto
list<string>c;
list<string>::iterator ite;
auto ite=find(c.begin(),c.emd(),target);
引用
指针:指向,指针指向的值还可以改变
引用:代表,一定要有初始化,初始化之后不能变化
x四个字节,指针4个字节(32位机器)
引用的常见用途:
参数传递、和返回值;
传引用更快,底层其实实现也是4个字节的指针,
下面两个相同的函数名称,下面两个一个引用,一个不加,是错误的,会产生二义性;
后面加const:是签名的一部分,两者可以同时存在;
对象模型
谈论的就是类和类之间的关系;
虚指针和虚表
子类的对象里面有父类的part;
继承:把数据继承下来,继承函数的调用权力,父类有虚函数,子类一定有虚函数;
A,B,C:总共有8个函数,有4个虚函数;
A有虚函数,虚指针指向虚表,几个虚函数虚表中就会有几个指针;
C *p=new c:
c->vfunc1();
静态绑定: 编译器看到调用动作,call xxx;调用函数,然后返回。
动态绑定: (指针调用,向上转型例如new一只猪,指向的动物,调用虚函数),指针调用虚函数,不能做静态绑定,看p的指向,寻找函数的过程是:指针—>虚指针---->虚表---->指向哪个函数;
*(p->vptr)[n](p);
(*p->vptr[n])(p);
n:虚函数的第几个虚函数
虚机制(动态绑定)
用容器存储指针,每个指针指向不同的函数,每个指针都是四个字节,实现不同的功能;遍历容器。
this指针
子类的对象调用父类的函数当然可以;执行到serialize到子类l里面的虚函数
所有成员函数都有一个隐藏的this指针,this指向子类,
动态绑定
a.vfunc():对象调用虚函数是静态绑定 call xxx;
动态绑定的三个条件:
- 通过指针来调用
- 存在向上转型,new一个B,但是类型却是父类A;
- 调用虚函数
pa->vfunc1():动态绑定
指针找到虚指针,然后在找到虚表,取中里面的第n个指针,然后调用函数,
const
函数的后面:修饰类的成员函数,不能在全局函数的后面放const,常函数,不打算改变类的成员变量,成员函数一般用来操作成员变量。
常量对象和非常量对象和常量成员函数和非常量成员函数关系如上图所示
常量对象可以调用常量成员函数;
常量对象不能调用非常量成员函数;
右边的函数字符串:加和不加const 签名不一样,设计两个函数;原因是因为共享,数据变化,常量字符串来调用,不必考虑COW,只能调用常量成员函数;
s[5]=assgin(a)
COW:Copy On Write;
当成员函数的const和non-const版本同时存在时:
常量对象只能调用常量的版本;
非常量对象只能调用非常量的版本;
new 和delete
内存管理和内存池,重载
下面强制使用全局的函数
new: 一个对象的大小;
new[]:大小
一个Foo对象的大小为4+4+4=12个字节;
Foo有虚函数,多一个虚指针,多4个字节;
对于3:是12*5=60吗????为什么是64呢。多了一个计数器,记录下面的大小为5,这个计数器的大小为4个字节,根据这个编译器就能很快速的知道调用5次构造函数和5次析构函数;
用全局的new和delete时会绕开自己写的
重载new(),delete()
palcement new 其中的第一个参数必须是size_t;
只有当new所调用的构造函数抛出异常的时候,才会调用这些重载版本的operator delete();
5按道理也应该调用相应的operator delete,但是没有,异常发出,如果没有人处理,一定会结束程序。
即使operator delete未能一一对应operator new,也不会出现任何的编译报错,去侦测抛出异常,
basic_string 使用new(extra)扩充申请量
palcement new 在字符串中的应用:有一个多的内存,多分配内存
new 、operator new 、array new、palcement new;