1.多态
1.1多态的定义
多态即多种形态,C + + 的多态分为静态多态和动态多态。
1. 静态多态就是重载,因为是在编译期决议确定,所以称为静态多态。
2. 动态多态就是通过继承重写基类的虚函数实现的多态,因为是在运行时决议确定,所以称为动态多态
1.2多态实现
- 虚函数重写
- 对象指针或引用(当父类指针/引用指向父类对象时调用的是父类的虚
函数,指向子类对象时调用的是子类的虚函数。)
2.探索虚函数表
2.1虚函数表定义
定义:
虚函数表是通过一块连续内存来存储虚函数的地址。
这里的地址并非函数真正的地址,而是call指令跳转后的地址。
这张表解决了继承、虚函数(重写)的问题。在有虚函数的对象实例中都存在一张虚函数表,虚函数表就像一张地图,指明了实际应该调用的虚函数函数。
2.2虚表的本质
虚表的本质:
虚表是一种数据结构,实质是一个指针数组,存放虚函数的地址,最后一个元素为0.
3.使用内存窗口验证虚表的存在
class Base
{
public :
virtual void func1()
{
cout<<"Base::func1" <<endl;
}
virtual void func2()
{
cout<<"Base::func2" <<endl;
}
private :
int a;
};
class Derive :public Base
{
public :
virtual void func1()
{
cout<<"Derive::func1" <<endl;
}
virtual void func3()
{
cout<<"Base::func3" <<endl;
}
int _d;
};
int main()
{
Base b;
Derive d;
system("pause");
return 0;
}
这里派生类继承了父类的虚函数表,并重写了func1函数,那么Derive::func3去哪了呢?(其实他就放在func1后面,这是vs的bug,vs将其处理了)
注意虚函数指针_vfptr后面还有一个0哦!通过内存查看
所谓眼见不一定为实,我们如何看到func3的地址呢,及其存在的位置呢?
接下来我们实现地址的显示:
4.探索单继承对象模型
typedef void(*VFUNC)();
void PrintVTable(int* vtable)//若想实现跨平台型可使用int** ,因为32为平台下,指针大小为4字节,64为平台下,指针大小8字节
{
printf("vtable:0x%p\n", vtable);
for (int i = 0; vtable[i] != 0; i++)
{
printf("vtable[%d]:0x%p->", i, vtable[i]);
VFUNC f = (VFUNC)vtable[i];
f();
}
cout << endl;
}
class Base
{
public :
virtual void func1()
{
cout<<"Base::func1" <<endl;
}
virtual void func2()
{
cout<<"Base::func2" <<endl;
}
private :
int a;
};
class Derive :public Base
{
public :
virtual void func1()//重写
{
cout<<"Derive::func1" <<endl;
}
virtual void func3()
{
cout<<"Base::func3" <<endl;
}
int _d;
};
int main()
{
Base b;
Derive d;
PrintVTable((int*)(*((int*)&b)));
PrintVTable((int*)(*((int*)&d)));
system("pause");
return 0;
}
5.探索多重继承的内存布局
5.1非菱形继承
typedef void(*VFUNC)();
void PrintVTable(int* vtable)
{
printf("vtable:0x%p\n", vtable);
for (int i = 0; vtable[i] != 0; i++)
{
printf("vtable[%d]:0x%p->", i, vtable[i]);
VFUNC f = (VFUNC)vtable[i];
f();
}
cout << endl;
}
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 Derive :public Base1,public Base2
{
public:
virtual void func1()
{
cout << "Derive::func1" << endl;
}
virtual void func3()
{
cout << "Base::func3" << endl;
}
int d;
};
int main()
{
Base1 b1;
Base2 b2;
Derive d1;
PrintVTable((int*)(*(int*)&b1));
PrintVTable((int*)(*(int*)&b2));
PrintVTable((int*)(*(int*)&d1));
PrintVTable((int*)(*((int*)((int)&d1 + sizeof(Base1)))));
system("pause");
return 0;
}
5.2菱形继承
typedef void(*VFUNC)();
void PrintVTable(int* vtable)
{
printf("vtable:0x%p\n", vtable);
for (int i = 0; vtable[i] != 0; i++)
{
printf("vtable[%d]:0x%p->", i, vtable[i]);
VFUNC f = (VFUNC)vtable[i];
f();
}
cout << endl;
}
class A
{
public:
virtual void f1()
{}
virtual void f2()
{}
int _a;
};
class B : virtual public A //虚继承
{
public:
virtual void f1()
{}
//virtual void f3()
//{}
int _b;
};
class C : virtual public A//虚继承
{
public:
virtual void f1()
{}
//virtual void f3()
//{}
int _c;
};
class D : public B, public C
{
public:
virtual void f1()
{
cout<<"D:f1()"<<endl;
}
virtual void f4()
{
cout<<"D:f4()"<<endl;
}
int _d;
};
int main()
{
D d;
cout<<sizeof(A)<<endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
cout << sizeof(D) << endl;
d._a = 1;
d._b = 2;
d._c = 3;
d._d = 4;
PrintVTable((int*)(*((int*)&d)));
system("pause");
return 0;
}
注意:
1. 虚函数虚继承
若为虚继承,子类的虚表内容只包含自己的虚函数指针,把父类的虚函数指针放在了公共区,并把这个公共区的地址放在了对象中。
2. 菱形继承
(1)有几个“含有虚表的父类”,子类就有几个虚表
(2)有几个“西继承同一个类的父类”,自雷就有几个虚基表指针
(3)子类还包括一个“虚函数虚继承产生的公共区域的指针”