什么是多态
所谓多态,也就是说“多种形态”
C++中虚函数就是为了实现多态
虚函数–类的成员函数前面加上virtual关键字,则这个函数就是虚函数
多态的形成条件:
1、虚函数的重写 2、父类的指针或者引用调用重写的虚函数
例如:A*p = & b;
A是一个父类,b是一个子类对象
这个时候就是形成了多态。这个时候调用函数与类型无关,只与指向的对象有关,指向谁就调用谁。
虚函数的重写:
当子类定义了一个与父类完全相同的虚函数(返回值,参数同,函数名)时,则称这个函数重写
特例:协变 A类虚函数的返回值可定义为A类的指针或引用 B类也是可以定义为B类的。(可以看做是切片类型)
class A
{
public:
A* Fun()
{}
}
class B :public A
{
public:
B* Fun()
{}
//在这里Fun函数就构成了重写,(协变)
}
单继承和多继承
单继承:
在这里要了解一下虚表:就是一个保存了虚函数的表
虚函数实现多态的原因就是因为有一个虚表指针指向虚函数表,这样就可以通过指针来找到虚函数
//打印虚表的函数
//单继承,多继承都会用
//32位平台下,指针是4个字节,我们只需要把它取出来就能把虚函数的地址打印出来了
typedef void(*V_FUNC)();//这里定义一个函数指针
void PrintVTable(int vtable)
{
int *VfArray = (int*) vtable;
printf("vtable:0x%p
",VfArray);
for(size_t i = 0;VfArray[i]!=0;++i)
{
printf("vfunc[%d]:0x%p
",i,VfArray);
V_FUNC f = (V_FUNC) VfArray[i];
f();
}
cout<<"=================================";
}
单继承的代码:
class Base
{
public:
virtual void Fun1()
{
cout<<"Base::Fun1()"<<endl;
}
virtual void Fun2()
{
cout<<"Base::Fun2()"<<endl;
}
private:
int _a;
};
class Derive:public Base
{
public:
virtual void Fun1()
{
cout<<"Derive::Fun1()"<<endl;
}
virtual void Fun3()
{
cout<<"Derive::Fun3()"<<endl;
}
private:
};
int main()
{
Base b;
Derive d;
PrintVTable(*((int*)&b));
PrintVTable(*((int*)&d));
}
单继承的对象模型如下图
多继承
class Base1
{
public:
void virtual Fun1()
{
cout<<"Base1::Fun1()"<<endl;
}
void virtual Fun2()
{
cout<<"Base1::Fun2()"<<endl;
}
private:
int _b;
};
class Base2
{
public:
void virtual Fun1()
{
cout<<"Base2::Fun1()"<<endl;
}
void virtual Fun3()
{
cout<<"Base2::Fun3()"<<endl;
}
private:
int _b;
};
class Derive:public Base1,public Base2
{
public:
void virtual Fun1()
{
cout<<"Derive::Fun1()"<<endl;//覆盖
}
void virtual Fun3()
{
cout<<"Derive::Fun3()"<<endl;
}
private:
int _d;
};
int main()
{
Base1 b1;
PrintVTable(*((int*)&b1));
Base2 b2;
PrintVTable(*((int*)&b2));
Derive d;
PrintVTable(*((int*)&d));
PrintVTable(*((int*)((char*)&d+sizeof(Base1))));
}
菱形虚拟继承
class Base
{
public:
void virtual Fun1()
{
cout<<"Base::Fun1()"<<endl;
}
void virtual Fun2()
{
cout<<"Base::Fun2()"<<endl;
}
public:
int _b;
};
class Derive1:virtual public Base
{
public:
void virtual Fun1()
{
cout<<"Derive1::Fun1()"<<endl;
}
void virtual Fun3()
{
cout<<"Derive1::Fun3()"<<endl;
}
public:
int _d1;
};
class Derive2:virtual public Base
{
public:
void virtual Fun1()
{
cout<<"Derive2::Fun1()"<<endl;
}
void virtual Fun4()
{
cout<<"Derive2::Fun4()"<<endl;
}
public:
int _d2;
};
class Derive:public Derive1,public Derive2
{
public:
void virtual Fun1()
{
cout<<"Derive::Fun1()"<<endl;//覆盖
}
void virtual Fun5()
{
cout<<"Derive::Fun5()"<<endl;
}
public:
int _d;
};
int main()
{
Derive d;
d._b = 2;
d._d1 = 3;
d._d2 = 4;
d._d = 5;
PrintVTable(*((int*)&d));
}
菱形虚拟继承对象模型如下图所示:
在菱形虚拟继承中:这里既有虚函数表,又有虚基表,要理解,就需要在编译代码的时候自己看一下内存中的具体情况。如图,可以看出,在菱形虚拟继承中,把基类的保存为公有的,这就需要用虚基表用偏移量找到他。这里注意虚函数的重写,因为看的是Derive的对象模型,所以在继承的时候,有的函数进行了重写。