为什么要使用多态
当定义的子类继承父类并重写父类的方法后,
父类使用指针调用子类的同名方法,得到的却是父类同名方法的结果
#include <iostream>
using namespace std;
class Father
{
public:void play() {cout << "一起去KTV唱歌吧" << endl;};
};class Son :public Father {
public:void play() {cout << "一起去打游戏吧!" << endl;};
};void testPlay(Father** man, int n) {for (int i = 0; i < n; i++) {man[i]->play();//man[i] = *man;}
}
int main(void) {Father father;Son son1, son2;Father* p[3] = { &father,&son1,&son2 };int len = sizeof(p) / sizeof(p[0]);testPlay(p, len);
}
使用多态后(父类方法声明时关键字virtual :虚函数):
是在父类方法声明的时候添加virtual关键字,实现的时候不需要添加
子类重写该方法的时候也可以添加,
父类
virtual void play() {
cout << "一起去KTV唱歌吧" << endl;
};子类
virtual void play() {
cout << "一起打游戏吧!" << endl;
};
多态的本质
形式上,使用 统一的父类指针做一般性处理,
但是实际执行时,这个 指针可以指向子类对象,
形式上,原本调用父类的方法,但是 实际上会调用子类的同名方法。
注意:程序执行时,父类指针指向父类对象,或子类对象时,在形式上是无法分辨的!只有通过多态机制,才能执行真正对应的方法。
虚函数表(32位下调试)
这里一个对象理应内存分布:一个虚函数指针+两个int成员数据(12个字节)
//虚函数是存放在虚函数表里的
//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针
virtual void fun1() {cout << "virtual:fun1()" << endl;}
virtual void fun2() { cout << "virtual:fun2()" << endl; }
virtual void fun3() { cout << "virtual:fun3()" << endl; }//普通成员函数在代码区
void fun4() { cout << "非虚函数:fun1()" << endl; }public:
int x = 200;
int y = 300;static int z;//静态成员数据在内存的全局数据区
测试
#include <iostream>
using namespace std;class Father{
public://虚函数是存放在虚函数表里的//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针virtual void fun1() {cout << "Father:fun1()" << endl; }virtual void fun2() { cout << "Father:fun2()" << endl; }virtual void fun3() { cout << "Father:fun3()" << endl; }//普通成员在代码区void fun4() { cout << "非虚函数:Father::fun4()" << endl; }int x = 200;int y = 300;static int z;//静态成员数据在内存的全局数据区
};
int Father::z = 0;
//定义一个void型函数指针
//virtual void fun1() {cout << "Father:fun1()" << endl;}
typedef void (*fun_t)(void);
int main(void) {Father father;cout << father.x << endl;//一个虚函数大小//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针,指向虚函数表//理应,这里只占12个字节cout << "sizeof(father)的大小:" << sizeof(father) << endl;cout << "对象的地址" << (int*)&father << endl;//先将father的值16进制的地址转换成int*的指针,在取值,然后再转换成int*的指针进行赋值int* vptr = (int*)(*(int*)&father);cout << "虚函数指针vptr的地址值" << vptr << endl;cout << "调用第一个虚函数:";((fun_t) * (vptr + 0))();//等同于调用void father::fun1(void);cout << "调用第二个虚函数:";((fun_t) * (vptr + 1))();//等同于调用void father::fun2(void);cout << "调用第三个虚函数:";((fun_t) * (vptr + 2))();//等同于调用void father::fun3(void);cout << "第一个数据成员的地址:" << endl;cout << &father.x << endl;cout << std::hex << (int) & father + 4 << endl;cout << "第一个数据成员的值:" << endl;cout <<std::dec<< father.x << endl;cout << *(int*)((int)&father + 4) << endl;cout << "第二个数据成员的地址:" << endl;cout << &father.y << endl;cout << std::hex << (int) & father + 8 << endl;cout << "第二个数据成员的值:" << endl;cout << std::dec <<father.y << endl;cout << *(int*)((int)&father + 8) << endl;return 0;
}
子类继承父类虚函数
子类虚函数的三种状态
完全继承父类
直接复制父类的虚函数表
子类重写父类的
在父类虚函数的对应位置进行替换
当父类再次指向子类的时候,子类中的虚函数表已经发生改变,父类这时候调用虚函数得到的就是子类的虚函数表中对应的东西
子类自己的虚函数
将新增的虚函数添加到已有虚函数表尾部
#include <iostream>
using namespace std;class Father{
public://虚函数是存放在虚函数表里的//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针virtual void fun1() {cout << "Father:fun1()" << endl; }virtual void fun2() { cout << "Father:fun2()" << endl; }virtual void fun3() { cout << "Father:fun3()" << endl; }//普通成员在代码区void fun4() { cout << "非虚函数:Father::fun4()" << endl; }int x = 200;int y = 300;static int z;//静态成员数据在内存的全局数据区
};
int Father::z = 0;class Son :public Father {
public://继承父类的虚函数virtual void fun1() { cout << "Son:fun1()" << endl; }//自己的虚函数virtual void fun4() { cout << "Son:fun4()" << endl; }
};//定义一个void型函数指针
//virtual void fun1() {cout << "Father:fun1()" << endl;}
typedef void (*fun_t)(void);int main(){Son son;int* vptr1 = (int*)*(int*)&son;cout << "son的地址:" << (int*) & son << endl;cout << "sizeof(son)的值:" << sizeof(son) << endl;for (int i = 0; i < 4; i++){cout << "调用第" << i + 1 << "个虚函数:";((fun_t) * (vptr1 + i))();}for (int i = 1; i <= 2; i++){cout << "第" << i << "个成员的值"<<endl;cout << son.x << endl;cout << *(int*)((int) & son + 4) * i << endl;}return 0;
}
使用多重继承的虚函数表
#include <iostream>
using namespace std;class Father{
public://虚函数是存放在虚函数表里的//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针virtual void fun1() {cout << "Father:fun1()" << endl; }virtual void fun2() { cout << "Father:fun2()" << endl; }virtual void fun3() { cout << "Father:fun3()" << endl; }//普通成员在代码区void fun4() { cout << "非虚函数:Father::fun4()" << endl; }int x = 200;int y = 300;static int z;//静态成员数据在内存的全局数据区
};
int Father::z = 0;
//另外一个基类
class Monther {
public://虚函数是存放在虚函数表里的//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针virtual void handel() { cout << "Monther:handl()" << endl; }virtual void hande2() { cout << "Monther:handl2()" << endl; }//普通成员在代码区void fun() { cout << "非虚函数:Father::fun4()" << endl; }int m = 400;int n = 600;static int z;//静态成员数据在内存的全局数据区
};class Son :public Father ,public Monther{
public://继承父类的虚函数virtual void fun1() { cout << "Son:fun1()" << endl; }//自己的虚函数virtual void fun4() { cout << "Son:fun4()" << endl; }//继承另外一个基类的虚函数virtual void hande2() { cout << "Son:handl2()" << endl; }
};//定义一个void型函数指针
//virtual void fun1() {cout << "Father:fun1()" << endl;}
typedef void (*fun_t)(void);int main(){Son son;int* vptr1 = (int*)*(int*)&son;cout << "第一个虚函数表的指针" << vptr1 << endl;//第二个虚函数表// 一个虚函数指针,两个成员数据int* vptr2 = (int*)*((int*)&son+3);cout << "第二个虚函数表的指针" << vptr2 << endl;cout << "son的地址:" << (int*) & son << endl;cout << "sizeof(son)的值:" << sizeof(son) << endl;for (int i = 0; i < 4; i++){cout << "调用第" << i + 1 << "个虚函数:";((fun_t) * (vptr1 + i))();}for (int i = 1; i <= 2; i++){cout << "第" << i << "个成员的值"<<endl;cout << *(int*)((int) & son + 4 * i) << endl;}for (int i = 1; i <= 2; i++) {cout << "继承母亲的第" << i << "个成员的值" << endl;cout << *(int*)((int)&son +12+ 4 * i) << endl;}for (int i = 0; i < 2; i++) {cout << "调用母亲的第" << i + 1 << "个虚函数:";((fun_t) * (vptr2 + i))();}return 0;
}
final关键字
设置该类不能被继承
class i1 {
};
class i2 final :public i1{};
class i3 :public i2{};
设置该成员函数不能被重写(final只能用于虚函数中)
class i1 {
virtual void chat()final {
cout << "聊天一代" << endl;
};
};
class i2 :public i1 {
virtual void chat();
};
override仅能虚函数(仅限函数声明时可以写)
作用:1. 提示程序的阅读者,这个函数是重写父类的功能。2. 防止程序员在重写父类的函数时,把函数名写错。
class i1 {
public:
virtual void chat() {
cout << "聊天一代" << endl;
};
};
class i2 :public i1 {
public:
virtual void chat()override;
};
消失的析构函(析构函数最好加上virtual)
#include <iostream>
#include <string>
using namespace std;class Father {
public:Father(const char* addr = "中国") {cout << __FUNCTION__ << endl;int len = strlen(addr) + 1;this->addr = new char[len];strcpy_s(this->addr,len, addr);};~Father() {cout << __FUNCTION__ << endl;if (addr) {delete[] addr;addr = NULL;}};
private:char* addr;
};
class Son:public Father {
public:Son(const char* addr = "中国",const char *game = "推箱子"):Father(addr) {cout << __FUNCTION__ << endl;int len = strlen(game) + 1;this->game = new char[len];strcpy_s(this->game, len, game);};~Son() {cout << __FUNCTION__ << endl;if (game) {delete[] game;game = NULL;}};
private:char* game;
};
int main(void) {string line(50, '-');Father* father = new Father();delete father;cout << line << endl;Son* son = new Son();delete son;cout << line << endl;Father* father1 = new Son();delete father1;cout << line << endl;}
上述可以看出
父类的通过子类定义的对象,释放之后,只释放了父类的空间,子类并没有释放;
解决:将父类的析构函数定义为虚函数
作用:当对父类的指针进行delete的时候,就会对该指针使用"动态析构"[如果这个指针是指向子类对象,那么就会先调用该子类的析构函数,然后再调用父类的]
virtual ~Father() {
纯虚函数和抽象函数
纯虚数(仅提供接口,实际方法由子类实现)
抽象类(拥有纯虚数的的类就是抽象类),抽象类无法创建对象
//把eat方法定义为纯虚数
virtual void eat() = 0;
1:纯虚函数一定要被实现才会结束抽象这个类 ,
2:要么不对这个纯虚函数做任何处理,等效于下一种情况(该方式不推荐)
3:要么继续把这个纯虚函数声明为纯虚函数,这个子类也成为抽象类virtual void eat() = 0;
#include <iostream>
#include <string>
using namespace std;class Shape {
public:Shape(const string& color = "白色") { this->color = color; }string getColor()const {return color;}//定义一个纯虚数virtual float area() = 0;
private:string color;
};class Circle :public Shape {
public:Circle(float radios, const string& color) :Shape(color),r(radios){};//实现父类的纯虚数float area() { return 3.14 * r * r; }
private:float r;
};
int main(void) {//Shape shape;Circle cir(2,"白色");cout<<cir.getColor()<<endl;cout <<cir.area()<<endl;
}