1.下面的代码,可以帮助大家理解C++的多态。
#include <iostream>
using namespace std;
// 只要类中有一个纯虚函数,那么A就是一个抽象类
class A
{
public:
//所有的接口,必须全部实现
virtual void Eat() = 0;// 纯虚方法、方法,变成了接口
virtual void Sleep() = 0;
virtual void Foot() = 0;
};
class Dog:public A
{
public:
virtual void Eat()//在子类里面virtual可以写,也可以不写
{
cout<<"Dog::Eat()"<<endl;
}
virtual void Sleep()
{
cout<<"Dog::Sleep()"<<endl;
}
virtual void Foot()
{
cout<<"Dog::Foot()"<<endl;
}
};
class Cat : public A
{
public:
virtual void Eat()//在子类里面virtual可以写,也可以不写
{
cout<<"Cat::Eat()"<<endl;
}
virtual void Sleep()
{
cout<<"Cat::Sleep()"<<endl;
}
virtual void Foot()
{
cout<<"Cat::Foot()"<<endl;
}
};
class Bird : public A
{
public:
virtual void Eat()//在子类里面virtual可以写,也可以不写
{
cout<<"Bird::Eat()"<<endl;
}
virtual void Sleep()
{
cout<<"Bird::Sleep()"<<endl;
}
virtual void Foot()
{
cout<<"Bird::Foot()"<<endl;
}
public:
virtual void Fly()
{
cout<<"Bird::Fly()"<<endl;
}
};
class Ostrich : public Bird// 鸵鸟公有继承鸟类
{
private:
void Fly()
{
cout<<"Bird::Fly()"<<endl;
}
};
//统一的接口
void Active(A *pa)
{
pa->Eat();
pa->Foot();
pa->Sleep();
}
int main()
{
Ostrich oo;
oo.Sleep();
// A a;//不能实例化A,A是个抽象基类
Dog d;
Cat c;
Active(&d);
Active(&c);
}
2.探究多态的深层次原因
#include <iostream>
using namespace std;
class Base
{
public:
virtual void func(){
cout<<"Base::func()"<<endl;
}
private:
int x;
};
class D: public Base
{
public:
void func(){
cout<<"D::func()"<<endl;
}
private:
int y;
};
int main()
{
cout<< sizeof(D)<<endl;// 有虚指针的话大小为12(x,y,虚指针),没有虚指针的话大小为8(x,y)
D d;
}
#include <iostream>
using namespace std;
class Base
{
public:
Base():y(0){
cout<<"Create Base object"<<endl;
}
public:
virtual void func(){
cout<<"Base::func()"<<endl;
}
virtual void list(){
cout<<"Base::list()"<<endl;
}
virtual void show(){
cout<<"Base::show()"<<endl;
}
void print(){
cout<<"Base::print()"<<endl;
}
private:
int y;
};
class D: public Base
{
public:
D():x(0){
cout<<"Create D object"<<endl;
}
public:
void func(){
cout<<"D::func()"<<endl;
}
void list(){
cout<<"D::list()"<<endl;
}
void print(){
cout<<"D::print()"<<endl;
}
private:
int x;
};
int main()
{
//cout<< sizeof(D)<<endl;
D d;
Base *pb = &d;//用父类的指针去接收子类对象的地址
pb->func();
return 0;
}
运行之后虚表的结构:
class Base
{
public:
virtual void f()
{ cout << "Base::f"<<endl;}
virtual void g()
{ cout << "Base::g"<<endl;}
virtual void h()
{ cout << "Base::h"<<endl;}
private:
int a;
int x;
};
typedef void(*pFun)();
void main()
{
Base b;
cout<<"&b = "<<&b<<endl;
cout<<"vfptr = "<<hex<<*(int*)(&b)<<endl;
pFun pfun = (pFun)*(((int*)*(int*)(&b))+0);
pfun();
pfun = (pFun)*(((int*)*(int*)(&b))+1);
pfun();
pfun = (pFun)*(((int*)*(int*)(&b))+2);
pfun();
}
从上面的代码证明了虚表的存在,我们可以分别取出在虚表中的函数,并执行这些函数。
上图可以看出来pfun指的是虚表中存储的第一个函数。单步调试往下执行,可以分别取出虚表中的函数。
#include<iostream>
using namespace std;
class Base
{
public:
Base()
{
cout<<"Create Base."<<endl;
}
virtual~Base()
{
cout<<"Free Base."<<endl;
}
};
class D : public Base
{
public:
D()
{
cout<<"Create D."<<endl;
}
~D()
{
cout<<"Free D."<<endl;
}
};
void main()
{
//D d;
Base *pb = new D;
delete pb;
}
基类指针,指向子类的对象(动态开辟空间),基类的析构函数加virtual,那么在析构pb时候,在析构完子类的时候,会自动的析构父类。
#include<iostream>
using namespace std;
class Base1
{
public:
virtual void f()
{ cout << "Base::f"<<endl;}
virtual void g()
{ cout << "Base::g"<<endl;}
virtual void h()
{ cout << "Base::h"<<endl;}
};
class Base2
{
public:
virtual void f()
{ cout << "Base::f"<<endl;}
virtual void g()
{ cout << "Base::g"<<endl;}
virtual void h()
{ cout << "Base::h"<<endl;}
};
class Base3
{
public:
virtual void f()
{ cout << "Base::f"<<endl;}
virtual void g()
{ cout << "Base::g"<<endl;}
virtual void h()
{ cout << "Base::h"<<endl;}
};
class D : public Base1, public Base2, public Base3
{
public:
virtual void f()
{ cout << "D::f"<<endl;}
virtual void g1()
{ cout << "D::g"<<endl;}
virtual void h1()
{ cout << "D::h"<<endl;}
};
void main()
{
D d;
}
多继承的时候,子类中重写的方法会覆盖父类虚表中的方法,三个虚表每个都要覆盖。没有重写的会跟在虚表的后面。