C++:虚函数相关

多态和虚函数

通过案例学多态
(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,就是其析构函数转换到运行时动态绑定

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

相关推荐

  1. C++:函数相关

    2024-07-14 06:16:04       28 阅读
  2. C++函数

    2024-07-14 06:16:04       46 阅读
  3. c++函数

    2024-07-14 06:16:04       54 阅读
  4. C++ 函数

    2024-07-14 06:16:04       44 阅读
  5. c++ 纯函数

    2024-07-14 06:16:04       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 06:16:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 06:16:04       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 06:16:04       58 阅读
  4. Python语言-面向对象

    2024-07-14 06:16:04       69 阅读

热门阅读

  1. helm系列之-构建自己的Helm Chart

    2024-07-14 06:16:04       22 阅读
  2. (算法)硬币问题

    2024-07-14 06:16:04       24 阅读
  3. 【代码复现】STAEformer

    2024-07-14 06:16:04       21 阅读
  4. python中的pickle模块和json模块

    2024-07-14 06:16:04       23 阅读
  5. ClickHouse实战第二章-ClickHouse 的安装调试

    2024-07-14 06:16:04       25 阅读
  6. Spring事件监听机制详解

    2024-07-14 06:16:04       22 阅读
  7. 案例:分库分表与SELECT * 发生的线上问题

    2024-07-14 06:16:04       24 阅读
  8. TypeScript的类型谓词与控制流分析

    2024-07-14 06:16:04       26 阅读