18.继承多态笔试题实战分析
Posted 为了财务自由!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18.继承多态笔试题实战分析相关的知识,希望对你有一定的参考价值。
class Animal
public:
Animal(string name) :_name(name)
// 纯虚函数
virtual void bark() = 0;
protected:
string _name;
;
// 以下是动物实体类
class Cat : public Animal
public:
Cat(string name) :Animal(name)
void bark() cout << _name << " bark: miao miao!" << endl;
;
class Dog : public Animal
public:
Dog(string name) :Animal(name)
void bark() cout << _name << " bark: wang wang!" << endl;
;
50-51:
p11[0]访问的是Cat前四个字节,p22[0]访问的是Dog前四个字节。
后续三行操作意思是交换前四个字节,那么Cat前四个字节放的就是Dog虚函数表地址(虚函数指针)Dog前四个字节放的就是Cat虚函数表地址(虚函数指针)
那么执行出来就是加菲猫汪汪叫,二哈喵喵叫!
class Base
public:
virtual void show(int i = 10)
cout << "call Base::show i:" << i << endl;
;
class Derive : public Base
public:
void show(int i = 20)
cout << "call Derive::show i:" << i << endl;
;
int main()
Base *p = new Derive(); // 虚析构函数
/*
push 0Ah => 函数调用,参数压栈是在编译时期就确定好的
mov eax, dword ptr[p]
mov ecx, dword ptr[eax]
call ecx
*/
p->show(); // 动态绑定 p-> Derive vfptr -> Derive vftable
delete p;
return 0;
调用的是派生类的方法,但是参数却是10?
编译阶段,p->show()编译器只能看到Base里的show方法,那么就将参数入栈:
push 0Ah => 函数调用,参数压栈是在编译时期就确定好的
接下来动态绑定(三句汇编):
mov eax, dword ptr[p]
mov ecx, dword ptr[eax]
call ecx
也就是说在编译时,10这个参数就入栈了!
class Base
private://public
virtual void show()
cout << "call Base::show" << endl;
;
class Derive : public Base
public:
void show()
cout << "call Derive::show" << endl;
;
int main()
Base* p = new Derive();
/*
成员方法能不能调用,就是说方法的访问权限是不是public的,是在编译阶段就需要确定
好的
编译阶段 Base::show
call Base::show call ecx
*/
//“Base::show”: 无法访问 private 成员(在“Base”类中声明)
p->show(); // 最终能调用到Derive::show,是在运行时期才确定的
delete p;
return 0;
class Base
public:
Base()
//进函数前 先开辟函数栈帧,然后把虚函数表放进去!:
/*
push ebp
mov ebp, esp
sub esp, 4Ch
rep stos esp<->ebp 0xCCCCCCCC(windows VS GCC/G++)
vfptr <- &Base::vftable
*/
cout << "call Base()" << endl;
clear();
//前四个字节为虚函数表地址,那么这个函数就把他变成0地址了...
//那么动态绑定的时候,就访问不到虚函数表了,0地址犯法!
void clear() memset(this, 0, sizeof(*this));
virtual void show()
cout << "call Base::show()" << endl;
;
class Derive : public Base
public:
Derive()
/*
push ebp
mov ebp, esp
sub esp, 4Ch
rep stos esp<->ebp 0xCCCCCCCC(windows VS GCC/G++)
vfptr <- &Derive::vftable
*/
cout << "call Derive()" << endl;
void show()
cout << "call Derive::show()" << endl;
;
int main()
//Base *pb1 = new Base();
/*
mov eax, dword ptr[pb1]
mov ecx, dword ptr[eax] eax:0x00000000 不是Base::vftable
call ecx
*/
//pb1->show(); // 动态绑定
//delete pb1;
Base *pb2 = new Derive();
// 动态绑定 call Derive::show()
/*
vfptr里面存储的是vftable的地址
vfptr <- vftable
*/
pb2->show();
//先调用Base构造函数,对虚函数表地址清零,然后调用Derive构造函数,
//进构造函数前,开辟函数栈帧,然后指向虚函数表,所以可以正常运行!
//而Base *pb1 = new Base();pb1->show();报错!
delete pb2;
return 0;
以上是关于18.继承多态笔试题实战分析的主要内容,如果未能解决你的问题,请参考以下文章
C++笔试试题讲解(~~~可能是全站唯独一份有解析的~~~)
动态内存函数+经典笔试题@动态内存管理---malloc +free + calloc + realloc