面向对象高级编程下
- 面向对象高级编程下
- 一. 转换函数
- 二. non-explict-one-argument ctor
- 三. explicit-one-argument ctor
- 四. pointer-like classes
- 1. 智能指针
- 2. 迭代器
- 五. function-like classes
- 六. namespace
- 七. 模板
- 1.类模板
- 2.函数模板
- 3.成员模板
- 八.模板特化和偏特化
- 1. 模板特化
- 2.模板偏特化
- 九.模板模板参数
- 十.可变参数模板
- 十一.auto
- 十二.reference
- 十三.虚指针和虚表
- 十四.关于this和动态绑定
- 十五.const
- 十六.重载operator new 和 operator delete
- placement new
面向对象高级编程下
一. 转换函数
设计一个类Fraction表示分数,包含分子和分母。我们希望它能自动转换为double类型,并参与运算。
当编译器执行到 double d = 4 + f;
这一行的时候,发现Fraction类型和一个整型或浮点型相加,首先找有没有重载+运算符,发现没有。然后找4能不能转换为Fraction类型,不能。最后找到转换函数,f可以转换为double类型。
转换函数的定义如下:
- operator是关键字,double是函数名,表示将Fraction转换为double类型,因为此处指明了输出类型,所以函数无返回值。
特点:
- 没有返回类型。
- 通常加const,因为不改变对象的数据成员的内容。
- 是将这种东西转换为别的东西。
考虑将Fraction转化为其它类型,如string。
二. non-explict-one-argument ctor
当编译器执行到 Fraction d2=f+4
这一行的时候,发现Fraction类里重载了+运算符,但是+右边应该是Fraction类型的对象。由于Fraction类的构造函数没有加explicit,因此编译器将4隐式转换为Fraction类型的对象(因为Fraction的构造函数第二个参数有默认值,因此4可以当成4,1),然后通过重载的+运算符计算新值,赋值给d2。
特点:
- 将别的东西转换为这种东西。
转换函数不能和non-explict-one-argument ctor共存
会出现二义性的问题。
三. explicit-one-argument ctor
明确告诉编译器,拒绝自动隐式转换。
explicit
关键字基本用在构造函数前面。
四. pointer-like classes
1. 智能指针
2. 迭代器
为什么operator->要这么写?如图右边区域所示,我们希望通过->去调用对象的某个函数,因为->返回的是指针,我们希望左值是一个指针,因此返回值是指针类型。
那么如何将指针传递出来呢?
我们可以调用operator*来先取得对象内容,然后加上取地址&,就可以获得指针了。
五. function-like classes
仿函数:重载了函数调用操作符
六. namespace
冒号作用域
:: 运算符是一个作用域。如果::前面什么都没有加,代表是全局作用域。
名字控制
namespace 本质是作用域,可以更好的控制标识符的作用域。
命名空间可以存放:变量、函数、类、结构体 …
命令空间的定义 必须定义在全局范围
命名空间可以嵌套命名空间
命名空间可以取别名, namespace newname = oldname;新名字与旧名字有同等效益
命名空间可以没有名字 ,没有名字相当于给命名空间 内的所有成员加上了static修饰。相当于只能被当前文件调用,属于内部链接属性
七. 模板
1.类模板
设计类的时候,考虑哪些类型可以允许使用者自行指定,那么设计为类模板。
2.函数模板
设计函数的时候,参数类型不影响函数的规则或实现,比如说比大小,那么设计为函数模板。
3.成员模板
本身是模板里的一个成员,同时自身又是模板。一般出现在构造函数中。
T1、T2是可以变化的,但是在T1、T2确定下来后,U1、U2又是可以变化的。
八.模板特化和偏特化
泛化也就是模板,特化就是指定模板中的具体类型。
1. 模板特化
2.模板偏特化
九.模板模板参数
函数模板是不支持模板的模板参数的,所以这儿所指的模板的模板参数就是类模板的模板参数,即对一个类模板,它的模板参数本身也是一个模板,更确切地说是一个类模板。
十.可变参数模板
十一.auto
十二.ranged-base for
十二.reference
十三.虚指针和虚表
-
可以发现子类对象中有父类的成分。
- 子类继承父类的数据和函数,函数继承的是调用权。
-
C++编译器看见函数调用有两种选择:静态绑定或者动态绑定。
- 符合某些条件会做动态绑定
- 1.必须通过指针来调用
- 2.指针是向上转型。(new的是子类,声明的是父类)
- 3.调用的是虚函数
- 其他时候是静态绑定。
- 符合某些条件会做动态绑定
十四.关于this和动态绑定
C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
我们可以打印一下this指针的值,然后打印对象的地址。
结果是一样的。
十五.const
对象有两种(const和非const),成员函数有两种(const和非const),四种情况中const对象不能调用非const成员函数(因为非const成员函数可能会修改class data,然而const对象又是不可以修改的)。
这种const只能用于成员函数,意思是不会修改class data。
十六.重载operator new 和 operator delete
重载全局
重载成员
当调用operator[]分配内存的时候,分配的内存大小加上4,这四个字节代表了分配的内存空间的大小。
placement new
我们可以重载operator new,写出多个版本,但是第一参数必须是size_t。
我们也可以重载operator delete,写出多个版本,但是它们绝不会被delete调用,只有当new所调用的构造函数抛出异常,才会调用这些版本。