2. 多态的定义及实现( 三 )


5. 单继承和多继承关系中的虚函数表 单继承:
多继承:
class Base1 {public:virtual void func1() { cout << "Base1::func1" << endl; }virtual void func2() {cout << "Base1::func2" << endl; }private:int b1;};class Base2 {public:virtual void func1() { cout << "Base2::func1" << endl;}virtual void func2() { cout << "Base2::func2" << endl;}private:int b2;};class Derive1 : public Base1, public Base2 {public:virtual void func1(){ cout << "Derive::func1" << endl; }virtual void func3() {cout << "Derive::func3" << endl;}private:int d1;};typedef void(*VFPTR) ();void PrintVTable(VFPTR vTable[]){cout << " 虚表地址>" << vTable << endl;for (int i = 0; vTable[i] != nullptr; ++i){printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);VFPTR f = vTable[i];f();}cout << endl;}int main(){Derive1 d;VFPTR* vTableb1 = (VFPTR*)(*(int*)&d);PrintVTable(vTableb1);VFPTR* vTableb2 = (VFPTR*)(*(int*)((char*)&d + sizeof(Base1)));PrintVTable(vTableb2);return 0;}
观察下图可以看出: 多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中
6. 继承和多态常见的面试问题
1. 下面哪种面向对象的方法可以让你变得富有( )
A: 继承 B: 封装 C: 多态 D: 抽象
2. ( )是面向对象程序设计语言中的一种机制 。这种机制实现了方法的定义与具体的对象无关,而对方法的
调用则可以关联于具体的对象 。
A: 继承 B: 模板 C: 对象的自身引用 D: 动态绑定
3. 面向对象设计中的继承和组合,下面说法错误的是?()
A:继承允许我们覆盖重写父类的实现细节,父类的实现对于子类是可见的,是一种静态复用,也称为
白盒复用
B:组合的对象不需要关心各自的实现细节,之间的关系是在运行时候才确定的,是一种动态复用,也
称为黑盒复用
C:优先使用继承,而不是组合,是面向对象设计的第二原则
D:继承可以使子类能自动继承父类的接口,但在设计模式中认为这是一种破坏了父类的封装性的表现
4. 以下关于纯虚函数的说法,正确的是( )
A:声明纯虚函数的类不能实例化对象 B:声明纯虚函数的类是虚基类
C:子类必须实现基类的纯虚函数 D:纯虚函数必须是空函数
5. 关于虚函数的描述正确的是( )
A:派生类的虚函数与基类的虚函数具有不同的参数个数和类型 B:内联函数不能是虚函数
C:派生类必须重新定义基类的虚函数 D:虚函数可以是一个型的函数
6. 关于虚表说法正确的是( )
A:一个类只能有一张虚表
B:基类中有虚函数,如果子类中没有重写基类的虚函数,此时子类与基类共用同一张虚表
C:虚表是在运行期间动态生成的
D:一个类的不同对象共享该类的虚表
7. 假设A类中有虚函数,B继承自A,B重写A中的虚函数,也没有定义任何虚函数,则( )
A:A类对象的前4个字节存储虚表地址,B类对象前4个字节不是虚表地址
B:A类对象和B类对象前4个字节存储的都是虚基表的地址
C:A类对象和B类对象前4个字节存储的虚表地址相同
D:A类和B类虚表中虚函数个数相同,但A类和B类使用的不是同一张虚表
8. 以下程序输出结果是什么()
class A
:
【2. 多态的定义及实现】 void func(int val = 1){ std::cout