c++ 07
一、多重继承
1)子类同时拥有两个或两个以上的基类,同时继承了所有基类的属性和行为。
销售员 经理
\ /
销售经理
汽车 客用特性 商用特性
\ | /
公共汽车
2)内存结构,按照继承表的顺序,从低到高地址一次排列各个基类子对象。将子类对象的地址隐式或者静态转换为基类指针,编译器会做地址计算,以保证基类指针的类型和其所指向的对象一致,但是重解释类型转换(reinterpret_cast)不做此计算。
3)防止名字冲突。或者由用户程序通过作用域限定解决冲突,或者借助using声明以重载的方式解决冲突,再或者通过汇聚替代,在汇聚子类中提供对产生冲突的函数的隐藏版本,并在该隐藏版本中通过正确的逻辑选择特定基类的实现。
4)钻石继承问题:公共基类子对象在最终子类对象中存在多个实例,沿着不同的继承路径所访问到的公共基类子对象可能不一样,由此导致数据不一致问题。
A
/ \
B C
\ /
D
为了解决钻石继承问题,需要设法让公共基类子对象在最终子类对象中仅有唯一的实例,且为所有中间子类对象所共享——虚继承。
二、多态
形状:位置,绘制
矩形:宽度、高度,绘制
圆形:半径,绘制
Shape
/ \
Rect Circle
如果将基类中的某个成员函数声明为虚函数,那么其子类中与该函数具有相同原型的成员函数就也成为虚函数,并对基类中的版本构成覆盖(override)。通过一个指向子类对象的基类指针,或者引用子类对象的基类引用,调用这个虚函数时,实际被调用的将是子类中的覆盖版本。这种特性被称为多态。
三、关于覆盖
1.基类中成员函数必须是虚函数。
2.子类中成员函数必须与基类中的虚函数拥有完全相同的函数名、形参表和常属性。
3.如果基类中的虚函数返回基本类型,那么子类覆盖版本的返回类型必须与基类完全相同。如果基类中的虚函数返回类类型的指针或者引用,那么子类覆盖版本的返回类型可以是基类返回类型的子类。
class X { ... };
class Y : public X { ... };
class A {
virtual int foo (void) { ... }
virtual X* bar (void) { ... }
};
class B : public A {
int foo (void) { ... }
Y* bar (void) { ... }
};
4.子类中的覆盖版本不能比基类版本抛出更多的异常。
5.子类中覆盖版本与基类版本的访控属性无关。
class A {
public:
virtual int foo (void) { ... }
};
class B : public A {
private
int foo (void) { ... }
};
B b;
b.foo (); // ERROR !
A* p = &b;
p -> foo (); // OK !
四、多态=虚函数+指针/引用
B b;
A a = (A)b;
a.foo (); // A::foo()
class A {
public:
void foo (void) {
this -> bar ();
}
virtual void bar (void) {
cout << 'A' << endl;
}
};
class B : public A {
private:
void bar (void) {
cout << 'B' << endl;
}
};
int main (void) {
B b;
b.foo (); // B
}
class A {
public:
A (void) {
this -> bar ();
}
~A (void) {
this -> bar ();
}
virtual void bar (void) {
cout << 'A' << endl;
}
};
class B : public A {
private:
void bar (void) {
cout << 'B' << endl;
}
};
int main (void) {
B b; // 'A'
}
五、虚函数的实现原理——虚函数表
class A {
public:
virtual void foo (void) { ... }
virtual void bar (void) { ... }
};
class B : public A {
public:
void foo (void) { ... }
};
编译器对于虚函数调用,不会根据调用者的类型生成对特定成员函数调用指令,相反生成一组特殊的指令,该组指令在运行时被执行,完成以下工作:
1)确定调用对象的真实类型;
2)从实际调用对象中获取虚函数表指针;
3)找到与所调用函数相对应的函数地址;
4)调用该函数。
——动态绑定(后期绑定)。
虚函数与普通成员函数相比,执行开销会更大,虚函数不能做内联优化。
六、纯虚函数、抽象类和纯抽象类
形如:
virtual 返回类型 函数名 (形参表) = 0;
的虚函数称为纯虚函数。
至少含有一个纯虚函数的类,称为抽象类。抽象类不能实例化对象。
除了构造函数和析构函数以外全部由纯虚函数组成类,称为纯抽象类。
七、运行时类型信息——RTTI
在运行阶段获得对象的类型信息的方法。
运算符:typeid
对象:typeinfo - name()、==、!=
支持多态。
dynamic_cast - 在多态父子类指针或引用之间转换。对于指针转换失败返回NULL,对于引用转换失败抛出bad_cast异常。
八、虚析构函数
将基类的析构函数定义为虚函数,delete一个指向子类对象的基类指针,实际被执行的就是子类的析构函数,而子类的析构函数又会自动调用基类的析构函数,从而保证子类和基类中所有的资源都被析构干净。
九、不是所有的函数都能定义为虚函数
构造函数
静态函数
全局函数
十、模板方法模式
class PDFReader {
public:
void open (const char* file) {
解析文本;
this -> drawText ();
解析矩形;
drawRect ();
}
virtual void drawText (void) = 0;
virtual void drawRect (void) = 0;
};
class PDFRender : public PDFReader {
void drawText (void) { ... }
void drawRect (void) { ... }
};
PDFRender pr;
pr.open ("1.pdf");
c++ 07的更多相关文章
- iOS系列 基础篇 07 Action动作和输出口
iOS系列 基础篇 07 Action动作和输出口 目录: 1. 前言及案例说明 2. 什么是动作? 3. 什么是输出口? 4. 实战 5. 结尾 1. 前言及案例说明 上篇内容我们学习了标签和按钮 ...
- javaSE基础07
javaSE基础07 一.static静态修饰符 用了static修饰的变量就会变成共享的属性,只会初始化一次,在内存中只存在一个,并且每个对象都可以访问,存放在方法区(数据共享区) 1.1 stat ...
- 《HelloGitHub月刊》第07期
最近工作上的事比较多,<HelloGitHub>月刊第07期拖到月底才发. 本期月刊对logo和月刊的排版进行了优化,不知道大家的反馈如何,还望大家多多反馈,让<HelloGitHu ...
- Python array,list,dataframe索引切片操作 2016年07月19日——智浪文档
array,list,dataframe索引切片操作 2016年07月19日——智浪文档 list,一维,二维array,datafrme,loc.iloc.ix的简单探讨 Numpy数组的索引和切片 ...
- 驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址
驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址 最近重新看了乾龙_Heron的<ARM 上电启动及 Uboot 代码分析>(下简称<代码分析>) ...
- NPOI 导入导出excel 支持 03 07
因为微软的office成本太高了,所以开发项目的时候电脑上没安装office,而是安装了wps.但开发语言用的是C#,所以直接调用微软的office组件是很方便的,但一方面慢,一方面成本高,所以从网上 ...
- Archlinux 2015.07.01 和 Windows7 双系统 安装教程
提前在windows7下给Archlinux预留一个分区,大小最好在20G以上(根据自己硬盘情况分配). 第一步,安装前的准备 从arch官网下载最新的ISO文件archlinux-2015.07.0 ...
- Java虚拟机JVM学习07 类的卸载机制
Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...
- AC日记——有趣的跳跃 openjudge 1.6 07
07:有趣的跳跃 总时间限制: 1000ms 内存限制: 65536kB 描述 一个长度为n(n>0)的序列中存在“有趣的跳跃”当前仅当相邻元素的差的绝对值经过排序后正好是从1到(n-1). ...
- AC日记——配对碱基链 openjudge 1.7 07
07:配对碱基链 总时间限制: 1000ms 内存限制: 65536kB 描述 脱氧核糖核酸(DNA)由两条互补的碱基链以双螺旋的方式结合而成.而构成DNA的碱基共有4种,分别为腺瞟呤(A).鸟嘌 ...
随机推荐
- linux下使用mutt发送带附件的邮件
echo "hello"|mutt -s "world" -a hack.jpg -- name@address.com
- VMware vSphere 5.5的12个更新亮点(1)
[IT专家网虚拟化]在VMworld 2013大会上发布的VMware vSphere 5.5版本提供的增强和改进,横跨从hypervisor到管理整个堆栈,提升了VMware的性能.可伸缩性和可用性 ...
- c++11: trailing return type in functions(函数返回类型后置)
In C++03, the return type of a function template cannot be generalized if the return type relies on ...
- aspx生成验证码
//定义方法 public partial class VerificationCode : System.Web.UI.Page { string ImagePath = &qu ...
- (转)Javascript面向对象编程(三):非构造函数的继承(作者:阮一峰)
不使用构造函数实现"继承". 一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese = { na ...
- iPhoneKeyboard
iPhoneKeyboard.Open static function Open (text : string, keyboardType : iPhoneKeyboardType = iPhoneK ...
- String.equals()
名称 说明 String.Equals(Obejecct) 确定String实例是否指 ...
- uva11426 欧拉函数应用
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=121873#problem/F 题目大意:给你一个数n,让你输出(i=1-> ...
- Codeforces round #353div2 C
题目来源:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=117863#problem/C 题目大意:给你n个数字,代表这个人在n个银行里面 ...
- VC++下使用SQLite数据库
老师最近给的上机题目有点变态,特别是写到最后,是需要写学生管理系统.如果C语言结合文件来操作的话,估计会比较麻烦(对文件里字符串的增删改查我都没有什么好点的算法).那就用数据库吧,我很自然的想到. 前 ...