厦门高端网站建设公司,国际新闻环球网,管理者的七项基本能力,万网企业邮箱1.多态的基本概念 多态是C面向对象三大特性之一多态分为两类 1. 静态多态:函数重载和运算符重载属于静态多态#xff0c;复用函数名 2.动态多态:派生类和虚函数实现运行时多态 静态多态和动态多态区别: 静态多态的函数地址早绑定–编译阶段确定函数地址 动态多态的函数地址晚绑… 1.多态的基本概念 多态是C面向对象三大特性之一多态分为两类 1. 静态多态:函数重载和运算符重载属于静态多态复用函数名· 2.动态多态:派生类和虚函数实现运行时多态 静态多态和动态多态区别: ·静态多态的函数地址早绑定–编译阶段确定函数地址 ·动态多态的函数地址晚绑定–运行阶段确定函数地址下面通过案例进行讲解多态 动态多态满足条件 1、有继承关系 2、子类重写父类的虚函数 动态多态使用 父类的指针或者引用执行子类对象 重写:函数返回值类型函数名参数列表完全—致称为重写 静态多态代码
#include iostream
using namespace std;
class dongwu {
public:void speak() {cout 动物叫 endl;}
};class cat :public dongwu {void speak() {cout 猫叫 endl;}
};
//早绑定编译阶段就确定函数的地址void speak(dongwu p) {p.speak();
}
void fun() {cat p;speak(p);
}
int main() {fun();cat p;//发生隐式转换,只能把儿子转为父亲退化dongwu m p;m.speak();return 0;
} 注意转化以及早绑定的特性是执行当前的类型的函数不执行儿子的函数 动态动态代码
#include iostream
using namespace std;
class dongwu {
public://virtual虚函数关键字virtual void speak() {cout 动物叫 endl;}
};class cat :public dongwu {//子类的virtual可加可不加virtual void speak() {cout 猫叫 endl;}
};//晚绑定执行子类的函数
void speak(dongwu p) {p.speak();
}
void fun() {cat p;speak(p);
}
int main() {fun();return 0;
} 二.多态的底层原理
我们先看以下代码
#include iostream
using namespace std;
class father1 {
public:void speak() {cout 动物叫 endl;}
};
class father2 {
public:virtual void speak() {cout 动物叫 endl;}
};
int main() {cout sizeof(father1) endl;cout sizeof(father2) endl;return 0;
} 当类的成员函数加入虚函数关键字后会发现类的大小发生了改变。此时类的内部结构。此时类的内部会多一个指针虚函数表指针虚函数指针指向虚函数表虚函数表中存储虚函数的入口地址。 那么当派生类继承基类后如果成员函数没有重名那么会完全继承父类的结构。 但是当派生类重写基函数的虚函数时派生类中的虚函数表会发生改变此时虚函数表指向派生类的虚函数基类的虚函数被覆盖。 此时我们有派生类隐式转换为基类时虚函数表中的内容并不改变此时调用虚函数执行的是派生类的虚函数。 三.多态的优点 1、组织结构清晰 2、可读性强 3、对于前期和后期扩展以及维护性高 普通计算机类:
#include iostream
using namespace std;
class jisuanqi {
public:int a, b;int jisuan(string fu) {if (fu ) {return a b;}else if (fu -) {return a - b;}else if (fu *) {return a * b;}}
};
void fun() {jisuanqi q;q.a 200;q.b 100;cout q.a - q.b q.jisuan(-) endl;cout q.a q.b q.jisuan() endl;cout q.a * q.b q.jisuan(*) endl;}
int main() {fun();return 0;
} 多态计算机类
#include iostream
using namespace std;
class jisuanqi {
public:int a;int b;virtual int jisuan() {return 0;}
};class add :public jisuanqi {virtual int jisuan() {return ab;}
};class jian :public jisuanqi {virtual int jisuan() {return a - b;}
};class cheng:public jisuanqi {virtual int jisuan() {return a * b;}
};void fun() {jisuanqi* p new add;p-a 200;p-b 100;cout p-a p-b p-jisuan()endl;delete p;p new jian;p-a 200;p-b 100;cout p-a - p-b p-jisuan()endl;delete p;p new cheng;p-a 200;p-b 100;cout p-a * p-b p-jisuan()endl;delete p;
}
int main() {fun();return 0;
} 四.纯虚函数和抽象类 在多态中通常父类中虚函数的实现是毫无意义的主要都是调用子类重写的内容因此可以将虚函数改为纯虚函数。当类中有了纯虚函数这个类也称为抽象类 纯虚函数语法: virtual 返回值类型 函数名︰参数列表 0 ; 抽象类特点: ·无法实例化对象 ·子类必须重写抽象类中的纯虚函数否则也属于抽象类 代码
#include iostream
using namespace std;class father {
public://纯虚函数virtual void fun() 0;
};class son :public father{
public:void fun() {cout 我是sond endl;}
};void fun() {//多态f必须是指针或者引用//father f; 报错不可实例化father* f new son;f-fun();
}
int main() {fun();return 0;
}案例制作饮品
#include iostream
using namespace std;
class father {
public:virtual void zhushui() 0;virtual void chongpao() 0;virtual void daoru() 0;virtual void jialiao() 0;void fun() {zhushui();chongpao();daoru();jialiao();}
};class tea :public father{void zhushui() {cout 煮山泉水 endl;};void chongpao() {cout 冲茶 endl;};void daoru() {cout 倒入茶杯中 endl;};void jialiao() {cout 加入枸杞 endl;};
};class kafei : public father{void zhushui() {cout 煮水 endl;};void chongpao() {cout 冲咖啡 endl;};void daoru() {cout 倒入咖啡杯中 endl;};void jialiao() {cout 加入奶和糖 endl;};
};
//函数接口
void fun(father* p) {p-fun();delete p;
}
int main() {fun(new tea);cout ---------- endl;fun(new kafei);return 0;
} 五. 虚析构和纯虚析构 多态使用时如果子类中有属性开辟到堆区那么父类指针在释放时无法调用到子类的析构代码解决方式: 将父类中的析构函数改为虚析构或者纯虚析构 虚析构和纯虚析构共性: ·可以解决父类指针释放子类对象·都需要有具体的函数实现 虚析构和纯虚析构区别: ·如果是纯虚析构该类属于抽象类无法实例化对象 代码
#include iostream
using namespace std;
class father {
public://纯虚函数virtual void fun() 0;father() {cout father构造函数 endl;}~father() {cout father析构函数 endl;}
};class son :public father {
public://堆区开辟数据son(int age) {cout son构造函数 endl;this-age new int(age);}~son() {cout son析构函数 endl;if (this-age ! NULL) {delete age;age NULL;}}void fun() {cout *age son的fun函数调用 endl;}int* age;
};
void fun() {father* p new son(21);delete p;
}
int main() {fun();return 0;
} 如图当发生多态时基类并不会调用子类的析构函数当子类中含有堆区开辟的空间时。会造成内存泄漏。此时需要虚析构或纯虚析构来解决。 虚析构代码
#include iostream
using namespace std;
class father {
public://纯虚函数virtual void fun() 0;father() {cout father构造函数 endl;}virtual ~father() {cout father析构函数 endl;}
};class son :public father {
public://堆区开辟数据son(int age) {cout son构造函数 endl;this-age new int(age);}~son() {cout son析构函数 endl;if (this-age ! NULL) {delete age;age NULL;}}void fun() {cout *age son的fun函数调用 endl;}int* age;
};
void fun() {father* p new son(21);delete p;
}
int main() {fun();return 0;
}
纯虚析构
#include iostream
using namespace std;
class father {
public://纯虚函数virtual void fun() 0;father() {cout father构造函数 endl;}virtual ~father() 0;
};
//纯虚函数必须
father::~father()
{cout father析构函数 endl;
}class son :public father {
public://堆区开辟数据son(int age) {cout son构造函数 endl;this-age new int(age);}~son() {cout son析构函数 endl;if (this-age ! NULL) {delete age;age NULL;}}void fun() {cout *age son的fun函数调用 endl;}int* age;
};
void fun() {father* p new son(21);delete p;
}
int main() {fun();return 0;
}
案例计算机
#include iostream
using namespace std;class CPU {
public://纯虚函数virtual void func() 0;
};class Memory_Module {
public://纯虚函数virtual void func() 0;
};class Graphics_card {
public://纯虚函数virtual void func() 0;
};class CPU_intel : public CPU {
public:void func() {cout intel的CPU工作 endl;}
};class Graphics_card_intel : public Graphics_card {
public:void func() {cout intel的显卡工作 endl;}
};class Memory_Module_intel : public Memory_Module {
public:void func() {cout intel的内存条工作 endl;}
};class CPU_lenovo: public CPU {
public:void func() {cout 联想的CPU工作 endl;}
};class Graphics_card_lenovo : public Graphics_card {
public:void func() {cout 联想的显卡工作 endl;}
};
class Memory_Module_lenovo : public Memory_Module {
public:void func() {cout 联想的内存条工作 endl;}
};
class computer {
public://当传入的是子类时发生多态computer() {};computer(CPU* CPU , Memory_Module* m, Graphics_card* g) {this-cpu CPU;this-m m;this-g g;}void work() {cpu-func();m-func();g-func();}
private:CPU* cpu;Memory_Module* m;Graphics_card* g;
};void fun() {CPU_lenovo* c1 new CPU_lenovo;CPU_intel* c2 new CPU_intel;Graphics_card_intel* g1 new Graphics_card_intel;Graphics_card_lenovo* g2 new Graphics_card_lenovo;Memory_Module_intel* m1 new Memory_Module_intel;Memory_Module_lenovo* m2 new Memory_Module_lenovo;cout 第一台电脑 endl;computer* com new computer(c1,m1,g1);com-work();cout ******************************** endl;cout 第二台电脑 endl;computer* com1 new computer(c2, m2, g2);com1-work();
}
int main() {fun();return 0;
}