概念:多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。
多态类别
(1)静态多态:静态多态通过函数重载和泛型编程实现,编译器在编译期间完成。
(2)动态多态:(也叫动态绑定)动态多态则通过虚函数来实现,在程序执行期间进行。被关键字virtual修饰的成员函数叫虚函数,当基类中有虚函数时,派生类要重写虚函数,以此来实现动态 绑定。
多态类别
(1)静态多态:静态多态通过函数重载和泛型编程实现,编译器在编译期间完成。
(2)动态多态:(也叫动态绑定)动态多态则通过虚函数来实现,在程序执行期间进行。被关键字virtual修饰的成员函数叫虚函数,当基类中有虚函数时,派生类要重写虚函数,以此来实现动态 绑定。
#include<iostream>
#include<stdlib.h>
using namespace std;
#include<stdlib.h>
using namespace std;
class Base
{
public:
virtual void funtest1()
{
cout << "funtest1" << endl;
}
int data = 9;
};
int main()
{
Base b;
cout << sizeof(b) << endl;
system("pause");
return 0;
}
我们可以看到,大小为8,那么里面除了一个int类型的数据外,就剩下一个虚函数了,都知道我们的int在32位平台下是4个字节,那么剩下的四个字节是什么呢?然后我们调试在取对象的地址跟一步看看
在里面我们可以看到我们的数据9,9的上面看起来像个地址,那他是不是指针呢,我们在上个实验的代码上在加两个虚函数,一个普通的成员函数看看
#include<iostream>
#include<stdlib.h>
using namespace std;
{
public:
virtual void funtest1()
{
cout << "funtest1" << endl;
}
int data = 9;
};
int main()
{
Base b;
cout << sizeof(b) << endl;
system("pause");
return 0;
}
我们可以看到,大小为8,那么里面除了一个int类型的数据外,就剩下一个虚函数了,都知道我们的int在32位平台下是4个字节,那么剩下的四个字节是什么呢?然后我们调试在取对象的地址跟一步看看
在里面我们可以看到我们的数据9,9的上面看起来像个地址,那他是不是指针呢,我们在上个实验的代码上在加两个虚函数,一个普通的成员函数看看
#include<iostream>
#include<stdlib.h>
using namespace std;
class Base
{
public:
virtual void funtest1()
{
cout << "funtest1" << endl;
}
virtual void funtest2()
{
cout << "funtest2" << endl;
}
virtual void funtest3()
{
cout << "funtest3" << endl;
}
void funtest4()
{
cout << "funtest4" << endl;
}
int _data = 9;
};
int main()
{
Base b;
cout << sizeof(b) << endl;
system("pause");
return 0;
}
运行结果依旧为8,然后我们继续调试跟进去看看
{
public:
virtual void funtest1()
{
cout << "funtest1" << endl;
}
virtual void funtest2()
{
cout << "funtest2" << endl;
}
virtual void funtest3()
{
cout << "funtest3" << endl;
}
void funtest4()
{
cout << "funtest4" << endl;
}
int _data = 9;
};
int main()
{
Base b;
cout << sizeof(b) << endl;
system("pause");
return 0;
}
运行结果依旧为8,然后我们继续调试跟进去看看
可以看到此时我们有三个虚函数了,我们取对象的地址后,在跟一步得到上图,我们三个虚函数恰好三个指针,是这样的吗?我们继续进行研究。
#include<iostream>
#include<stdlib.h>
using namespace std;
#include<stdlib.h>
using namespace std;
class Base
{
public:
virtual void funtest1()
{
cout << "funtest1" << endl;
}
virtual void funtest2()
{
cout << "funtest2" << endl;
}
virtual void funtest3()
{
cout << "funtest3" << endl;
}
void funtest4()
{
cout << "funtest4" << endl;
}
int _data = 9;
};
typedef void(*POINT)();//定义一个函数指针
void print()
{
Base b;
POINT *p = (POINT*)(*(int*)&b);
while (*p)
{
(*p)();
++p;
}
}
int main()
{
print();
system("pause");
return 0;
}
{
public:
virtual void funtest1()
{
cout << "funtest1" << endl;
}
virtual void funtest2()
{
cout << "funtest2" << endl;
}
virtual void funtest3()
{
cout << "funtest3" << endl;
}
void funtest4()
{
cout << "funtest4" << endl;
}
int _data = 9;
};
typedef void(*POINT)();//定义一个函数指针
void print()
{
Base b;
POINT *p = (POINT*)(*(int*)&b);
while (*p)
{
(*p)();
++p;
}
}
int main()
{
print();
system("pause");
return 0;
}
我们定义一个函数指针类型,然后让他++,结果可以看到,我们看的p的值就正是表的地址,指向那块表。我们把这块表叫虚表。
可见,这个指针指向了一块虚表,而虚表里的东西又指向了每个虚函数,在这个测试的时候我们仅仅是给了一个类去看的,我们下来给一个派生类去公有继承这个类,但并不给派生类里面放东西,也不重写基类的虚函数,然后看看对象模型是怎么样的。
#include<iostream>
#include<stdlib.h>
using namespace std;
#include<stdlib.h>
using namespace std;
class Base
{
public:
virtual void funtest1()
{
cout << "Base:funtest1" << endl;
}
virtual void funtest2()
{
cout << "Base:funtest2" << endl;
}
virtual void funtest3()
{
cout << "Base:funtest3" << endl;
}
void funtest4()
{
cout << "Base:funtest4" << endl;
}
int _data = 9;
};
class Dervied :public Base
{
{
public:
virtual void funtest1()
{
cout << "Base:funtest1" << endl;
}
virtual void funtest2()
{
cout << "Base:funtest2" << endl;
}
virtual void funtest3()
{
cout << "Base:funtest3" << endl;
}
void funtest4()
{
cout << "Base:funtest4" << endl;
}
int _data = 9;
};
class Dervied :public Base
{
};
typedef void(*POINT)();//定义一个函数指针
void print()
{
Base b;
cout << "Base:" << endl;
POINT *p = (POINT*)(*(int*)&b);
while (*p)
{
(*p)();
++p;
}
Dervied d;
cout << " Dervied:" << endl;
POINT *q = (POINT*)(*(int*)&d)
int main()
{
print();
system("pause");
return 0;
}
typedef void(*POINT)();//定义一个函数指针
void print()
{
Base b;
cout << "Base:" << endl;
POINT *p = (POINT*)(*(int*)&b);
while (*p)
{
(*p)();
++p;
}
Dervied d;
cout << " Dervied:" << endl;
POINT *q = (POINT*)(*(int*)&d)
int main()
{
print();
system("pause");
return 0;
}
我们反汇编一下,看一下派生类的构造函数做了什么
结论:可以看到在没有重写虚函数且派生类里面也没有放东西的情况下,派生类的构造函数调用了基类的构造函数。此时派生类和基类公用一张虚表。
下面我们只部分的重写基类的虚函数,查看结果
#include<iostream>
#include<stdlib.h>
using namespace std;
#include<stdlib.h>
using namespace std;
class Base
{
public:
virtual void funtest1()
{
cout << "Base:funtest1" << endl;
}
virtual void funtest2()
{
cout << "Base:funtest2" << endl;
}
virtual void funtest3()
{
cout << "Base:funtest3" << endl;
}
void funtest4()
{
cout << "Base:funtest4" << endl;
}
int _data = 9;
};
class Dervied :public Base
{
public:
void funtest1()
{
cout << "Dervied:funtest1" << endl;
}
void funtest2()
{
cout << "Dervied:funtest2" << endl;
}
virtual void funtest5()
{
cout << "Dervied:funtest5" << endl;
}
{
public:
virtual void funtest1()
{
cout << "Base:funtest1" << endl;
}
virtual void funtest2()
{
cout << "Base:funtest2" << endl;
}
virtual void funtest3()
{
cout << "Base:funtest3" << endl;
}
void funtest4()
{
cout << "Base:funtest4" << endl;
}
int _data = 9;
};
class Dervied :public Base
{
public:
void funtest1()
{
cout << "Dervied:funtest1" << endl;
}
void funtest2()
{
cout << "Dervied:funtest2" << endl;
}
virtual void funtest5()
{
cout << "Dervied:funtest5" << endl;
}
};
typedef void(*POINT)();//定义一个函数指针
void print()
{
Base b;
cout << "Base:" << endl;
POINT *p = (POINT*)(*(int*)&b);
while (*p)
{
(*p)();
++p;
}
typedef void(*POINT)();//定义一个函数指针
void print()
{
Base b;
cout << "Base:" << endl;
POINT *p = (POINT*)(*(int*)&b);
while (*p)
{
(*p)();
++p;
}
cout << " Dervied:" << endl;
POINT *q = (POINT*)(*(int*)&d);
while (*q)
{
(*q)();
++q;
}
}
void print1()
{
Dervied d;
cout << " Dervied:" << endl;
POINT *p = (POINT*)(*(int*)&d);
while (*p)
{
(*p)();
++p;
}
}
int main()
{
print();
print1();
system("pause");
return 0;
}
POINT *q = (POINT*)(*(int*)&d);
while (*q)
{
(*q)();
++q;
}
}
void print1()
{
Dervied d;
cout << " Dervied:" << endl;
POINT *p = (POINT*)(*(int*)&d);
while (*p)
{
(*p)();
++p;
}
}
int main()
{
print();
print1();
system("pause");
return 0;
}
结论:我们公有继承了基类,一般来说入股基类有虚函数,派生类就一定要重写虚函数,而我在写这个派生类的时候,只重写写了两个虚函数。我们可以看到在派生类中没有重写的虚函数,编译器还是给我们打印了出来;
对派生类而言整个顺序就是(1)先拷基类的虚表
(2)如果重写了虚函数,就替换基类相同位置上的虚函数
(3)最后加上派生类自己的虚函数
虚函数的调用:(1)先通过虚表指针找到虚表
(2)然后在虚表里找到函数所在位置。
上面我们说了单继承的虚函数,现在我们一起来看一下多继承的虚函数,
#include<iostream>
#include<stdlib.h>
using namespace std;
#include<stdlib.h>
using namespace std;
class Base1
{
public:
virtual void funtest0()
{
cout << "Base1:funtest0" << endl;
}
virtual void funtest1()
{
cout << "Base1:funtest1" << endl;
}
virtual void funtest2()
{
cout << "Base1:funtest2" << endl;
}
int a1 = 9;
};
class Base2
{
public:
virtual void funtest3()
{
cout << "Base2:funtest3" << endl;
}
virtual void funtest4()
{
cout << "Base2:funtest4" << endl;
}
int a2 = 10;
};
{
public:
virtual void funtest0()
{
cout << "Base1:funtest0" << endl;
}
virtual void funtest1()
{
cout << "Base1:funtest1" << endl;
}
virtual void funtest2()
{
cout << "Base1:funtest2" << endl;
}
int a1 = 9;
};
class Base2
{
public:
virtual void funtest3()
{
cout << "Base2:funtest3" << endl;
}
virtual void funtest4()
{
cout << "Base2:funtest4" << endl;
}
int a2 = 10;
};
class Dervied :public Base1,public Base2
{
public:
virtual void funtest1()
{
cout << "Dervied:funtest1" << endl;
}
virtual void funtest3()
{
cout << "Dervied:funtest3" << endl;
}
virtual void funtest5()
{
cout << "Dervied:funtest5" << endl;
}
};
typedef void(*POINT)();//定义一个函数指针
void print()
{
Dervied d;
cout << "Dervied:" << endl;
POINT *p = (POINT*)(*(int*)&d);
while (*p)
{
(*p)();
++p;
}
Base2& b = d;
cout <<endl;
POINT *q = (POINT*)(*(int*)&b);
while (*q)
{
(*q)();
++q;
}
}
int main()
{
print();
system("pause");
return 0;
}
{
public:
virtual void funtest1()
{
cout << "Dervied:funtest1" << endl;
}
virtual void funtest3()
{
cout << "Dervied:funtest3" << endl;
}
virtual void funtest5()
{
cout << "Dervied:funtest5" << endl;
}
};
typedef void(*POINT)();//定义一个函数指针
void print()
{
Dervied d;
cout << "Dervied:" << endl;
POINT *p = (POINT*)(*(int*)&d);
while (*p)
{
(*p)();
++p;
}
Base2& b = d;
cout <<endl;
POINT *q = (POINT*)(*(int*)&b);
while (*q)
{
(*q)();
++q;
}
}
int main()
{
print();
system("pause");
return 0;
}
运行结果:
我们来分析一下,求出派生类的大小为20,派生类d公有继承自b1和b2,所以此时的d中就有了两个虚表,根据打印的虚表我们可以看出,我们派生类自己的虚函数跟在了第一张虚表上,或者说他属于第一张虚表。