多态定义:多种形式或形态
多态分类
静态多态:在编译期间完成,编译器根据函数实参的类型推断出要调用哪个函数。
在这里我们只说函数重载,泛型编程在后面再进行介绍。
函数重载的条件
(1)在同一作用域
(2)函数名相同,参数不同
(3)返回值可以不同
动态多态;在程序执行期间判断所引用对象的实际类型,根据其实际类型调用相应的方法。
实现动态多态的条件
1.必须是虚函数
关于虚函数
使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类必须对其进行重写。
将基类的某一个成员函数定义为虚函数,在派生类中该函数始终保持虚函数的特
性。
只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。
重写也称覆盖,函数重写的条件
(1)不在同一作用域(分别在基类和派生类)
(2)函数原型相同(函数名相同,参数相同,返回值相同)
(3)基类函数必须有virtual关键字
(4)访问修饰符可以不同
2.通过基类类型的引用或者指针调用虚函数
虚表:
对于有虚函数的类,编译器都会维护一张虚表,对象的前4个字节就是指向虚表的指针。
下面来看一个派生类将基类的虚函数重写的例子,分析一下基类和派生类各自的虚函数表
class Base
{
public:
virtual void Funtest1()
{
cout << "Base::Funtest1()" << endl;
}
virtual void Funtest2()
{
cout << "Base::Funtest2()" << endl;
}
virtual void Funtest3()
{
cout << "Base::Funtest3()" << endl;
}
};
class Derived :public Base
{
public:
virtual void Funtest1()
{
cout << "Derived::Funtest1()" << endl;
}
virtual void Funtest4()
{
cout << "Derived::Funtest4()" << endl;
}
virtual void Funtest5()
{
cout << "Derived::Funtest5()" << endl;
}
};
typedef void(*PVFT)();
void PrintVFTable(Base& b)
{
PVFT* pvtf = (PVFT*)(*(int*)&b);
while (*pvtf)
{
(*pvtf)();
pvtf++;
}
}
int main()
{
Derived d;
Base b;
Base& b1 = b;
b1=d;
PrintVFTable(b1);
system("pause");
return 0;
}
单继承派生类的虚函数表生成
1.先拷贝基类的虚函数表生成;
2.如果派生类重写了基类的某个虚函数,就用派生类重写后的虚函数替换相同偏移量位置的虚函数;
3.如果派生类有新增的虚函数,跟在基类的虚函数地址后面。
class B1
{
public:
B1()
{
_b1 = 0;
}
virtual void fun1()
{
cout << "B1::fun1()" << endl;
}
virtual void fun2()
{
cout << "B1::fun2()" << endl;
}
private:
int _b1;
};
class B2
{
public:
B2()
{
_b2 = 1;
}
virtual void fun3()
{
cout << "B2::fun3()" << endl;
}
virtual void fun4()
{
cout << "B2::fun4()" << endl;
}
private:
int _b2;
};
class D :public B1, public B2
{
public:
D()
{
_d = 2;
}
virtual void fun1()
{
cout << "D::fun1()" << endl;
}
virtual void fun3()
{
cout << "D::fun3()" << endl;
}
virtual void fun5()
{
cout << "D::fun5()" << endl;
}
private:
int _d;
};
typedef void(*PVTF)();
void PrintVpt(B1& b1, const char* _table)
{
cout << _table << endl;
PVTF* pVtf = (PVTF*)(*(int*)&b1);
while (*pVtf)
{
(*pVtf)();
++pVtf;
}
cout << endl;
}
void PrintVpt(B2& b2, const char* _table)
{
cout << _table << endl;
PVTF* pVtf = (PVTF*)(*(int*)&b2);
while (*pVtf)
{
(*pVtf)();
++pVtf;
}
cout << endl;
}
void test()
{
D d;
B1& b1 = d;
B2& b2 = d;
PrintVpt(b1, "D-->B1 vpf:");
PrintVpt(b2, "D-->B2 vpf:");
}
int main()
{
test();
system("pause");
return 0;
}
多继承多态派生类对象模型
多继承派生类的虚函数表生成
多继承派生类虚函数的顺序
1.如果派生类对B1中虚函数重写,替换相同位置的虚函数;
2.如果派生类对B2中虚函数重写,替换相同位置的虚函数;
3.如果派生类有自己新增的函数,放在第一张虚表之后。
多态下的菱形虚拟继承
class B
{
public:
B()
{
_b = 1;
}
virtual void fun1()
{
cout << "B::fun1()" << endl;
}
virtual void fun2()
{
cout << "B::fun2()" << endl;
}
private:
int _b;
};
class C1:virtual public B
{
public:
C1()
{
_c1 = 2;
}
virtual void fun1()
{
cout << "C1::fun1()" << endl;
}
virtual void fun3()
{
cout << "C1::fun3()" << endl;
}
private:
int _c1;
};
class C2 :virtual public B
{
public:
C2()
{
_c2 = 3;
}
virtual void fun4()
{
cout << "C2::fun4()" << endl;
}
private:
int _c2;
};
class D :public C1, public C2
{
public:
D()
{
_d = 4;
}
virtual void fun1()
{
cout << "D::fun1()" << endl;
}
virtual void fun4()
{
cout << "D::fun4()" << endl;
}
virtual void fun5()
{
cout << "D::fun5()" << endl;
}
private:
int _d;
};
typedef void(*PVTF)();
void PrintVpt(void* p, const char* _table)
{
cout << _table << endl;
PVTF* pVtf = (PVTF*)(*(int*)p);
while (*pVtf)
{
(*pVtf)();
++pVtf;
}
cout << endl;
}
void test()
{
D d;
B& b = d;
PrintVpt(&b, "D-->B vpf:");
C1& c1 = d;
PrintVpt(&c1, "D-->C1 vpf:");
C2& c2 = d;
PrintVpt(&c2, "D-->C2 vpf:");
}
int main()
{
test();
system("pause");
return 0;
}
菱形虚拟继承派生类的对象模型
派生类的虚表生成
成员函数的调用过程
1.是否为虚函数
2.若为虚函数,找虚表指针->虚函数地址->调用相应的虚函数;若为非虚函数,直接调用相应的函数。