尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C++学习日记 Day10:多态

C++学习日记 Day10:多态 ## 今天学了什么今天学习C的多态。## 多态的分类静态多态函数重载、运算符重载、模板复用函数名动态多态派生类和虚函数实现运行时。*注静态多态和静态函数/静态变量static没有关系只是相对于动态多态的叫法。①静态多态和动态多态的区别静态多态的函数地址早绑定编译阶段 确定函数地址动态多态的函数地址晚绑定运行阶段 确定函数地址②动态多态的满足条件有继承关系子类要重写父类的虚函数③动态函数的使用父类的指针或者引用要指向子类对象④多态的优点代码组织结构清晰可读性强利于前期和后期的扩展和维护## 纯虚函数和抽象类纯虚函数在多态中通常父类虚函数用处不大主要都是子类调用重写由此可以改为纯虚函数。语法virtual 返回值类型 函数名参数列表0抽象类当类中有纯虚函数这个类也称为抽象类。抽象类的特点①无法实例化对象②子类必须重写抽象类中的纯虚函数否则也属于抽象类。## 虚析构和纯虚析构虚析构语法virtual ~ 类名{}纯虚析构语法class Base{…virtual ~ 类名{}0}…类名::~类名{ …}问题在多态使用时子类中有属性开辟到堆区父类指针在释放时无法调用子类的析构函数造成内存泄漏解决方法将父类的析构改为虚析构/纯虚析构;验证class Animal { public: Animal() { cout Animal 构造函数 endl; } virtual void speak() 0; ~Animal() { cout Animal 虚析构函数 endl; } }; class Cat:public Animal { public: Cat(string name) { cout Cat 构造函数 endl; m_name new string(name); } virtual void speak() { cout * m_name小猫在说话 endl; } ~Cat() { if (m_name!NULL) { cout Cat 析构函数 endl; delete m_name; m_name NULL; } } string* m_name; }; void test() { Animal* an new Cat(Tom); an-speak(); delete an; }运行发现打印结果没有cat的析构函数在speak处下断点进入调试发现在执行完speak函数以后直接进入了Animal的析构函数并没有进入Cat的析构函数所以导致cat类的m_name指针无法释放。将父类的析构改为虚析构重复调试步骤发现这一次进入了cat的析构函数验证成功。虚析构和纯虚析构的共性可以解决父类指针释放子类对象都需要有具体的函数实现区别纯虚析构的类属于抽象类无法实例化对象。*注如果子类中没有堆区数据可以不写虚析构/纯虚析构。## 练习1.利用多态实现计算器#includeiostream using namespace std; class calculator { public: virtual int getResult() { return 0; } int num1; int num2; }; class Addcalculator:public calculator { public: int getResult() { return num1 num2; } }; class Subcalculator :public calculator { public: int getResult() { return num1 - num2; } }; class Mulcalculator :public calculator { public: int getResult() { return num1 * num2; } }; void test() { calculator* cal new Addcalculator; cal-num1 10; cal-num2 10; cal-getResult(); cout cal-num1 cal-num2 cal-getResult() endl; delete cal; cal new Subcalculator; cal-num1 10; cal-num2 10; cout cal-num1 - cal-num2 cal-getResult() endl; delete cal; cal new Mulcalculator; cal-num1 10; cal-num2 10; cout cal-num1 * cal-num2 cal-getResult() endl; delete cal; } int main() { test(); return 0; }## 补充虚函数调用链Animal *pnew Dog();p-speak();顺序1.p是父类指针指向Dog类的对象2.Dog对象内部有_vfptrvirtual function pointer虚函数指针3._vfptr指向Dog类的虚函数表4.虚函数表中[0]是Dog::speak5.最终执行Dog::speak。
返回列表