一、多态的概念
所谓的多态性,就是不同的对象收到相同的消息时产生不同的动作,即同一个函数名下定义的不同功能的函数,这些函数执行不同但又有类似的操作,从而可以使用相同的方式来调用这些不同功能的同名函数,即“一个接口,多种方法”。
二、多态的分类
1.静态多态(重载函数 模板等):
编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式的类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。
2.动态多态(虚函数等):
动态绑定:在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的的方法。
动态绑定的条件(两个条件必须同时满足):
(1)必须是虚函数;
(2)通过基类的引用或指针调用函数。
使用virtual关键字修饰类的成员函数时,注明该函数时虚函数,派生类需要重新实现,编译器将实现动态绑定。
三、关于:函数重载、同名隐藏、重写举例
函数重载:
//函数重载
int add(int x, int y)
{
return x + y;
}
double add(float x, float y)
{
return x + y;
}
int main()
{
int a = 1, b = 2;
int ret1 = a + b;
float c = 3.14f, d = 2.2f;
float ret2 = c + d;
cout <<"int: "<<ret1 << endl;
cout << "double: "<<ret2 << endl;
system("pause");
return 0;
}
重写:
class Base
{
public:
virtual Base& fun(int x, int y)
{
a = x;
b = y;
cout << "Base::" << a << " " << b << endl;
return *this;
}
private:
int a;
int b;
};
class Derived:public Base
{
public:
Derived& fun(int x, int y)
{
c = x + y;
cout << "Derived::" << c << endl;
return *this;
}
private:
int c;
};
int main()
{
Base b;
Derived d;
b.fun(1, 2);
d.Derived::fun(5, 6);
system("pause");
return 0;
}
同名隐藏:
//同名隐藏
class Base
{
public:
int show()
{
cout << "Base::show()" << endl;
return 0;
}
};
class Derived :public Base
{
public:
void show()
{
cout << "Derived::show()" << endl;
}
};
int main()
{
Derived d;
d.show();
d.Base::show();
system ("pause");
return 0;
}
四、虚表剖析
对于有虚函数的类(即抽象类),编译器都会维护一张虚表,对象的前四个字节存储的就是指向虚表的指针,虚表中按照虚函数在类中声明的顺序依次存放了各个虚函数的地址。
1.单继承中的模型
//没有覆盖且派生类没有添加虚函数
class B
{
public:
virtual void Funtest1()
{
cout << "B::Funtest1" << endl;
}
virtual void Funtest2()
{
cout << "B::Funtest2" << endl;
}
virtual void Funtest3()
{
cout << "B::Funtest3" << endl;
}
virtual void Funtest4()
{
cout << "B::Funtest4" << endl;
}
};
class D :public B
{};
typedef void (*Vpf)(); //函数指针
void PrintVpf()
{
D b;
Vpf* fun = (Vpf*)*(int*)&b;
while (*fun)
{
(*fun)();
fun++;
}
}
int main()
{
cout << sizeof(B) << endl;
cout << sizeof(D) << endl;
PrintVpf();
system("pause");
return 0;
}
单继承继承规则:
1.如果派生类没有重写基类的虚函数,并且没有添加自己的虚函数,则直接继承基类的虚函数;
2.若派生类新增了虚函数,则虚表先存放基类继承来的虚函数,再存放派生类的虚函数,之后存放派生类自己的虚函数。
3.若基类中有虚函数被派生类重写,派生类中重写的虚函数会替换基类中被重写虚函数的位置,之后存放派生类新添加的虚函数。
2.多继承:
class B1
{
public:
virtual void Funtest1()
{
cout << "B1::Funtest1" << endl;
}
};
class B2
{
public:
virtual void Funtest2()
{
cout << "B2::Funtest2" << endl;
}
};
class D:public B1, public B2
{
public:
virtual void Funtest3()
{
cout << "D::Funtest3" << endl;
}
};
typedef void (*Vpf)();
void PrintVpf()
{
D d;
Vpf* fun = (Vpf*)*(int*)&d;
cout << endl<< "D类:" << endl;
while (*fun)
{
(*fun)();
++fun;
}
B2 &b2 = d;//打印B2的虚表
fun = (Vpf*)*(int*)&b2;
while (*fun)
{
(*fun)();
++fun;
}
}
int main()
{
cout << "sizeof(B1) = "<<sizeof(B1) << endl;
cout << "sizeof(D) = "<<sizeof(D) << endl;
PrintVpf();
system("pause");
return 0;
}
多继承规则:没有重写的多函数的虚表,先按照继承次序打印第一个基类虚表,在打印派生类新添加的虚表,之后打印第二个基类的虚表。若有重写则转变为单继承问题。
3.虚拟继承:
菱形继承示例模型分析:
//菱形虚拟继承
class B
{
public:
virtual void Funtest1()
{
cout << "B::Funtest1" << endl;
}
int _data1;
};
class C1 :virtual public B
{
public:
virtual void Funtest2()
{
cout << "C1::Funtest2" << endl;
}
int _data2;
};
class C2 :virtual public B
{
public:
virtual void Funtest3()
{
cout << "C2::Funtest3" << endl;
}
int _data3;
};
class D :public C1, public C2
{
public:
virtual void Funtest4()
{
cout << "D::Funtest4" << endl;
}
int _data4;
};
typedef void(*Vft)();
void PrintVft()
{
D d;
d.C1::_data1 = 1;
d._data2 = 2;
d._data3 = 3;
d._data4 = 4;
cout << endl << "C1的虚表里存放的虚函数:" << endl;
//由于D多继承于C1和C2,所以D中的虚函数存放于C1的虚表里
Vft* fun1 = (Vft*)*(int*)&d;//此处指向的是C1的虚表,包含三个虚函数
while (*fun1)
{
(*fun1)();
fun1++;
}
cout << endl << "C2的虚表里存放的虚函数:" << endl;
Vft* fun2 = (Vft*)*((int*)&d + 3);//向后偏移12个字节找到C2的虚表指针,包含两个虚函数
while (*fun2)
{
(*fun2)();
fun2++;
}
cout << endl << "B的虚表里存放的虚函数:" << endl;
Vft* fun3= (Vft*)*((int*)&d + 7);//向后偏移4*3+4*3+4=28个字节找到B的虚表指针,包含一个虚函数
(*fun3)();
}
int main()
{
cout << "sizeof(B) = " << sizeof(B) << endl;
cout << "sizeof(C1) = " << sizeof(C1) << endl;
cout << "sizeof(C2) = " << sizeof(C2) << endl;
cout << "sizeof(D) = " << sizeof(D) << endl;
PrintVft();
system("pause");
return 0;
}