多态和虚函数
通过案例学多态
(1)案例:父类Animal,2个子类Dog和Cat,实现speak方法
(2)用父类指针指向各对象,调用各方法看效果,记下来
(3)将父类speak方法声明为virtual,再用父类指针调用各方法看效果,记下来
(4)对比差异,理解什么叫多态
#include
#include
// 基类:Furniture
class Furniture {
public:
// 虚函数表示颜色
virtual std::string getColor() {
std::cout << "基类:DiningTable color: " << std::endl;
}
// 虚析构函数
virtual ~Furniture() {}
};
// 子类:Sofa
class Sofa : public Furniture {
private:
std::string color;
public:
// 构造函数
Sofa(const std::string &c) : color© {}
// 实现getColor方法
std::string getColor() {
std::cout << "子类:Sofa color: " << std::endl;
return color;
}
};
// 子类:DiningTable
class DiningTable : public Furniture {
private:
std::string color;
public:
// 构造函数
DiningTable(const std::string &c) : color© {}
// 实现getColor方法
std::string getColor() {
std::cout << "子类:DiningTable color: " << std::endl;
return color;
}
};
int test070201() {
// 创建Sofa和DiningTable对象
Furniture tmp;
std::cout << tmp.getColor() << std::endl;
Furniture *mySofa = new Sofa(“Red”);
Furniture *myDiningTable = new DiningTable(“Brown”);
// 输出它们的颜色
std::cout << "Sofa color: " << mySofa->getColor() << std::endl;
std::cout << "DiningTable color: " << myDiningTable->getColor() << std::endl;
// 释放内存
delete mySofa;
delete myDiningTable;
return 0;
}
什么是多态
(1)polymorphism,多态,面向对象的三大特征之一。
(2)从宏观讲,多态就是要实现一套逻辑多种具体适配的执行结果。猫就应该是猫的叫声,狗就应该是狗的叫声。
(3)从微观讲,多态就是要一套代码在运行时根据实际对象的不同来动态绑定/跳转执行相匹配的具体函数
(4)函数声明前加virtual的即是虚函数
(5)虚函数是C++实现多态特性的基础,从语法上讲多态特性的基类方法必须是虚函数
多态中的override
(1)基类中方法声明为virtual,派生类中重新实现同名方法以实现多态,这就叫override(中文为覆盖,或重写)
(2)注意区分override和redefining,微观上最大区别就是是否有virtual,宏观上最大区别就是是否表现为多态
对比下三个概念
(1)overload,重载 同一个类里面的多个方法,函数名相同但参数列表不同
(2)redifining,重定义,隐藏 继承中子类再次实现父类中同名方法然后把父类方法隐藏掉
(3)override,覆盖,重写 继承中子类去实现父类中同名virtual方法然后实现多态特性
纯虚函数与抽象类
纯虚函数
(1)纯虚函数就是基类中只有原型没有实体的一种虚函数
(2)纯虚函数形式:virtual 函数原型=0;
(3)代码实践:在基类Animal中使用纯虚函数
(4)纯虚函数为什么没有实体?因为语义上不需要
(5)纯虚函数是否占用内存?不会,因为纯虚函数所在的类根本无法实例化对象
#include <iostream>
#include <string>
// 基类:Furniture
class Furniture {
public:
// 虚函数表示颜色
virtual std::string getColor() const = 0;//纯虚函数
// 虚析构函数
virtual ~Furniture() {}
};
// 子类:Sofa
class Sofa : public Furniture {
private:
std::string color;
public:
// 构造函数
Sofa(const std::string& c) : color(c) {}
// 实现getColor方法
std::string getColor() const override {
return color;
}
};
// 子类:DiningTable
class DiningTable : public Furniture {
private:
std::string color;
public:
// 构造函数
DiningTable(const std::string& c) : color(c) {}
// 实现getColor方法
std::string getColor() const override {
return color;
}
};
int main() {
// 创建Sofa和DiningTable对象
Furniture* mySofa = new Sofa("Red");
Furniture* myDiningTable = new DiningTable("Brown");
// 输出它们的颜色
std::cout << "Sofa color: " << mySofa->getColor() << std::endl;
std::cout << "DiningTable color: " << myDiningTable->getColor() << std::endl;
// 释放内存
delete mySofa;
delete myDiningTable;
return 0;
}
抽象类(abstract type)
(1)带有纯虚函数的类成为抽象类。抽象类只能作为基类来派生新类,不可实例化对象。
(2)派生类必须实现基类的纯虚函数后才能用于实例化对象。
(3)抽象类的作用:将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。对应暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。这种机制可以让语法和语义保持一致。
(4)抽象类的子类必须实现基类中的纯虚函数,这样子类才能创建对象,否则子类就还是个抽象类
虚析构函数
什么是虚析构函数
(1)析构函数前加virtual,则析构函数变为虚析构函数
(2)规则:基类有1个或多个虚函数时(注意不要求是纯虚函数),则其析构函数应该声明为virtual
注意:虚函数都可以,纯虚函数当然也可以
/ 基类:Furniture
class Furniture {
public:
// 虚函数表示颜色
virtual std::string getColor() const = 0; //纯虚函数
// 虚析构函数
virtual ~Furniture() { std::cout << " ~Furniture " << std::endl; }
};
// 子类:Sofa
class Sofa : public Furniture {
private:
std::string color;
public:
// 构造函数
Sofa(const std::string &c) : color(c) {}
// 实现getColor方法
std::string getColor() const override { return color; }
~Sofa() { std::cout << " ~Sofa " << std::endl; }
};
// 子类:DiningTable
class DiningTable : public Furniture {
private:
std::string color;
public:
// 构造函数
DiningTable(const std::string &c) : color(c) {}
// 实现getColor方法
std::string getColor() const override { return color; }
~DiningTable() { std::cout << " ~DiningTable " << std::endl; }
};
int test070201() {
// 创建Sofa和DiningTable对象
Furniture *mySofa = new Sofa("Red");
Furniture *myDiningTable = new DiningTable("Brown");
// 输出它们的颜色
std::cout << "Sofa color: " << mySofa->getColor() << std::endl;
std::cout << "DiningTable color: " << myDiningTable->getColor() << std::endl;
// 释放内存
delete mySofa;
delete myDiningTable;
return 0;
}
为什么需要虚析构函数
(1)代码演示:父子类各自添加析构函数,用2种分配和回收对象的方式分别实验,观察析构函数被调用的规律
(2)结论:虚析构函数在各种情况下总能调用正确的(和对象真正匹配的)析构函数。
总结
多态就是当父类类型的指针指向的是子类的变量时,指针调用的方法还是子类的方法,是运行时决定的
实现的方法就是虚函数,即在父类方法前添加关键词virtual
纯虚函数基类中只有原型没有实体的一种虚函数
纯虚函数也可以实现多态
有纯虚函数的类成为抽象类,可以包含其他普通方法、数据成员,不可实例化
基类有一个虚函数,析构函数前需要添加virtual
在析构函数前添加virtual,就是其析构函数转换到运行时动态绑定
学习记录,侵权联系删除。
来源:朱老师物联网大课堂