钟表商城网站建设方案,澧县网站建设,做如美团式网站要多少钱,做网站配置服务器注#xff1a;visual studio复制当前行粘贴到下一行#xff1a; CTRLD 杂项
调用子类重写的虚函数#xff08;带默认参数#xff09;#xff0c;但参数用的是基类的虚函数中的默认参数#xff1a;
这是由于参数是在编译时压入
试题一
交换两个基类指针指向的对象的vf… 注visual studio复制当前行粘贴到下一行 CTRLD 杂项
调用子类重写的虚函数带默认参数但参数用的是基类的虚函数中的默认参数
这是由于参数是在编译时压入
试题一
交换两个基类指针指向的对象的vfptr造成的运行结果变化
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; }
};int main()
{Animal* p1 new Cat(加菲猫);Animal* p2 new Dog(二哈);int* p11 (int*)p1;int* p22 (int*)p2;int temp p11[0]; // p11[0]访问Cat的前4个字节,即 指向Cat的vftable的vfptrp11[0] p22[0]; // p22[0]访问Dog的前4个字节,即 指向Dog的vftable的vfptrp22[0] temp;// 上面代码相当于交换了虚函数表指针// 导致下面调用虚函数时就发生了非预期的情况p1-bark(); // 实际调用Dog::bark()p2-bark(); // 实际调用Cat::bark()delete p1;delete p2;return 0;
}
试题二
有如下代码
#include iostream
#include string
using namespace std;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();p-show();delete p;return 0;
}
// 输出结果
// call Derive::show i:10发现调用的是派生类覆盖的函数确实是动态绑定但使用的参数却是基类虚函数的默认参数而不是派生类重写的虚函数的默认值。
原因是函数调用参数压栈是在编译时期具体call函数可以在运行时p-show() 汇编指令大致如下
push 0Ah # 压入基类的默认实参10
mov eax, dword ptr[p]
mov ecx, dword ptr[eax]
call ecx试题三
利用多态能调用到派生类private成员函数
#include iostream
#include string
using namespace std;class Base
{
public:virtual void show(int i 10){cout call Base::show endl;}
};
class Derive : public Base
{
private:void show(int i 20){cout call Derive::show endl;}
};
int main()
{Base* p new Derive();// 成员方法限定符是在【编译时】检查由于编译时通过p检查的是Base::show(),没有问题// 而运行时调用子类覆盖的成员这不影响函数执行p-show(); // 最终调用到Derive::show(),是在运行时期确定delete p;return 0;
}// 输出结果call Derive::show如果把基类的虚函数访问权限设置为private,则在编译阶段无法通过
试题四
说明下面代码段一和二是否正确执行说明理由
#include iostream
#include string
using namespace std;class Base
{
public:Base(){cout call Base() endl;clear();}// !!!!!!!!!!!!!!!!!!!!!!!!void clear() { memset(this, 0, sizeof(*this)); }virtual void show(){cout call Base::show() endl;}
};
class Derive : public Base
{
public:Derive(){cout call Derive() endl;}void show(){cout call Derive::show() endl;}
};
int main()
{// 代码段一Base* pb1 new Base();pb1-show();delete pb1;// 代码段二/*Base* pb2 new Derive();pb2-show();delete pb2;*/return 0;
}解答
代码段一执行失败
因为new Base()调用构造函数时进入第一行代码前会生成vfptr就是将vftable地址写入其中指向Base类对应的虚函数表但是在构造函数中后面又调用clear函数将内存清0导致vfptr被置零随后调用 pb1-show(); 时会使用vfptr则会造成非法访问运行时提示
引发了异常: 读取访问权限冲突。
pb1-**** 是 nullptr。
代码段二执行成功
执行 new Derive(); 时先调用基类构造虽然在构造函数中也会使vfptr被清零但是随后调用派生类构造会将子类的vftable地址赋值给vfptr所以导致最后通过 pb2-show(); 访问vfptr是没问题的