例题一
#include <iostream>
using namespace std;
class Animal
{
public:
Animal(string name) :name_(name) {
}
virtual void bark() = 0;
protected:
string getName() {
return name_; }
private:
string name_;
};
class Cat : public Animal {
public:
Cat(string name) : Animal(name){
}
void bark() {
cout << "Cat " << getName() << "miao miao miao" << endl;
}
};
class Dog : public Animal {
public:
Dog(string name) : Animal(name) {
}
void bark() {
cout << "Dog " << getName() << "wang wang wang" << endl;
}
};
int main()
{
Animal* cat = new Cat("罗小黑");
Animal* dog = new Dog("布鲁托");
int* p = (int*)cat;
int* q = (int*)dog;
int tmp = p[0];
p[0] = q[0];
q[0] = tmp;
cat->bark();
dog->bark();
}
运行结果: Dog 罗小黑wang wang wang
Cat 布鲁托miao miao miao
原因:将Cat与Dog的虚表指针vfptr交换了,导致调用的函数互换了。
例题二
class Base {
public:
virtual void show(int i = 10)
{
cout << "Base::show() " << i << endl;
}
};
class Drived : public Base
{
public:
virtual void show(int i = 20)
{
cout << "Drived::show() " << i << endl;
}
};
int main()
{
Base* b = new Drived;
b->show();
}
运行结果 Drived::show() 10
原因:编译阶段,会将基类的show()函数,如果该函数有默认形参那么将其形参默认值入栈。但是运行时期,是调用的虚函数表的函数地址。
具体汇编代码如下,
b->show();
00007FF66DED2692 mov rax,qword ptr [b]
00007FF66DED2696 mov rax,qword ptr [rax]
00007FF66DED2699 mov edx,0Ah // 基类的show()默认形参10
00007FF66DED269E mov rcx,qword ptr [b]
00007FF66DED26A2 call qword ptr [rax]
例题三
class Base {
public:
virtual void show()
{
cout << "Base::show() " << endl;
}
};
class Drived : public Base
{
private:
virtual void show()
{
cout << "Drived::show() " << endl;
}
};
int main()
{
Base* b = new Drived;
b->show();
delete b;
}
运行结果:Drived::show()
原因:编译阶段,编译器首先是否拥有函数访问权限。代码中,使用的是基类指针,所以编译器检查的是基类中show()的权限。而具体调用的show()是在运行阶段,因为基类使用虚函数,所以调用show()的时候动态绑定。尽管派生类的show()函数是私有的,但是其地址是在虚函数表中,因此从虚表中调用派生类的show()函数。
例题四
class Base {
public:
Base()
{
cout << "Base Construct" << endl;
clear();
}
void clear(){
memset(this, 0, sizeof(*this));
}
virtual void show()
{
cout << "Base::show() " << endl;
}
};
class Drived : public Base
{
public:
Drived() {
cout << "Drived Construct" << endl;
}
virtual void show()
{
cout << "Drived::show() " << endl;
}
};
int main()
{
/*Base* b1 = new Base(); // 运行错误
b1->show();*/
Base* b2 = new Drived; // 运行失败
b2->show();
}