9. C++虚函数与多态

简介: 9. C++虚函数与多态

虚函数

virtual修饰的成员函数就是虚函数

  • 虚函数对类的内存影响:需要增加一个指针类型的内存大小
  • 无论多少虚函数,只会增加一个指针类型的内存大小
  • 虚函数表的概念: 指向虚函数的指针

  • 我们自己也可以通过虚函数表指针去访问函数(一般做这样的操作不写数据类型)
#include <iostream>
#include <string>
using namespace std;
class MM 
{
public:
  virtual void print()        //1.会写
  {
    cout << "第一个虚函数" << endl;
  }
  virtual void printData() 
  {
    cout << "第二个虚函数" << endl;
  }
protected:
};
int main() 
{
  cout << sizeof(MM) << endl;     //2.对类内存影响
  MM mm;
  mm.print();
  mm.printData();
  //了解一下.32位没问题,64位 vs2022 问题
  int** pObject = (int **)(&mm);
  typedef void(*PF)();
  PF pf = (PF)pObject[0][0];
  pf();           //调用第一个虚函数
  pf = (PF)pObject[0][1];
  pf();           //调用第二个虚函数
  return 0;
}

纯虚函数

具有一个或者多个纯虚函数的类型称之为抽象类,抽象类特性:

  • 抽象类不能创建对象
  • 抽象类可以创建对象指针

纯虚函数也是一个虚函数,所以也需要virtual修饰,纯虚函数是没有函数体,函数=0;

#include <iostream>
using namespace std;
//抽象类
class MM 
{
public:
  //纯虚函数
  virtual void print() = 0;
protected:
  string name;
};
int main() 
{
  //MM object;   抽象类不能构建对象
  MM* pMM = nullptr;
  return 0;
}

虚析构函数

virtual修饰的析构函数 就是虚析构函数

  • 当父类指针被子类对象初始化的时候需要用虚析构函数
  • 所有析构函数底层解析其实函数名相同
#include <iostream>
#include <string>
using namespace std;
class MM 
{
public:
  void print() 
  {
    cout << "MM::print" << endl;
  }
  virtual ~MM()         //虚析构函数
  {
    cout << "~MM" << endl;
  }
};
class Son :public MM 
{
public:
  void print() 
  {
    cout << "Son::print" << endl;
  }
  ~Son() 
  {
    cout << "~Son" << endl;
  }
};
int main() 
{
  MM* pMM = new Son;   //构造子类对象,必须构造父类对象在构造自身
  pMM->print();    //MM看类型
  delete pMM;
  pMM = nullptr;
  return 0;
}

虚函数和多态

多态的概念并不重要,重要的是需要知道那个对象指针在特定情况调用那个成员才是重要

多态概念:  指在继承中指针的同一行为的不同结果,举个栗子(男生和女生上厕所,都是上厕所的行为,男生站着,女生蹲着)

实现多态的两个前提条件:

  • 必须是public继承
  • 必须父类存在virtual类型的成员函数,并且子类中存在该函数的同名函数
  • 一定存在指针的引用
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
  void print()
  {
    cout << "MM::print" << endl;
  }
  virtual void printData() 
  {
    cout << "MM virtual printData" << endl;
  }
  virtual ~MM()         //虚析构函数
  {
    cout << "~MM" << endl;
  }
};
class Son :public MM
{
public:
  void print()
  {
    cout << "Son::print" << endl;
  }
  void printData() 
  {
    cout << "Son printData" << endl;
  }
  ~Son()
  {
    cout << "~Son" << endl;
  }
};
int main() 
{
  //正常对象的访问,不存在多态
  //都是就近原则
  cout << "正常对象访问" << endl;
  MM mmobject;
  mmobject.print();
  mmobject.printData();
  Son sonobject;
  sonobject.print();
  sonobject.printData();
  //正常的指针访问
  cout << "正常指针访问" << endl;
  MM* pMM = new MM;
  pMM->print();
  pMM->printData();
  Son* pSon = new Son;
  pSon->print();
  pSon->printData();
  //非正常的初始化
  //父类指针被子类初始化
  cout << "不正常的指针赋值" << endl;
  MM* pObject = new Son;
  pObject->print();       //没有virutal 看指针类型 调用MM::print
  pObject->printData();     //有virtual 看对象 调用Son::printData
  pObject = new MM;
  pObject->printData();     //调用MM中
  
  cout << "引用类型" << endl;
  MM& girl = sonobject;
  girl.print();
  girl.printData();
  return 0;
}

虚函数在继承特殊现象

#include <iostream>
#include <string>
using namespace std;
class A
{
public:
  virtual void print()
  {
    cout << "A" << endl;
  }
  virtual void printData() final   //禁止子类重写方法
  {
    cout << "A" << endl;
  }
};
//final: 父类中用来禁止子类重写同名方法
//override: 强制重写,起说明作用,表示当前子类当前方法是重写父类
class B :public A 
{
public:
  //重写:子类实现父类虚函数的同名函数
  void print() override
  {
    cout << "B" << endl;
  }
  //void printData(){}  //final禁止重写
};
class C :public B 
{
public:
  void print() 
  {
    cout << "C" << endl;
  }
};
int main() 
{
  B* pb = new C;
  pb->print();      //调用C::print
  pb = new B;
  pb->print();      //调用B::print
  return 0;
}

纯虚函数和ADT

ADT: 抽象数据类型

抽象类本身不能创建对象,但是子类如果重写类父类中纯虚函数,子类是可以被允许创建对象

抽象类一般用于架构项目,构建好整个项目模块,具体细致工作可以交给子类去实现

采用ADT方式设计项目,可以把这个模块构建出来,并且测试代码也可以提前完成。

#include <iostream>
using namespace std;
//抽象产品类
class AbstractProduct 
{
public:
  virtual void printProduct() = 0;
};
//抽象系统类---ADT
//析构函数一定写虚析构函数
class AbstractSystem 
{
public:
  ~AbstractSystem() {}
  virtual void insertData(AbstractProduct* product) = 0;
  virtual void printData()const = 0;
  virtual int size() const = 0;
  virtual bool empty() const = 0;
};
class ArraySystem :public AbstractSystem 
{
public:
  void insertData(AbstractProduct* product) 
  {
  }
  void printData()const 
  {
  }
  int size() const 
  {
    return 0;
  }
  bool empty() const 
  {
    return 0;
  }
};
class ListSystem :public AbstractSystem
{
public:
  void insertData(AbstractProduct* product)
  {
  }
  void printData()const
  {
  }
  int size() const
  {
    return 0;
  }
  bool empty() const
  {
    return 0;
  }
};
int main() 
{
  AbstractSystem* p =new  ArraySystem;
  p->printData();
  //UI中用的比较多
  //MFC --->不需要自己创建,只需要重写一个,构建对象即可
  p = new ListSystem;
  p->printData();
  return 0;
}
目录
相关文章
|
8天前
|
C++
【C++】从零开始认识多态(二)
面向对象技术(oop)的核心思想就是封装,继承和多态。通过之前的学习,我们了解了什么是封装,什么是继承。 封装就是对将一些属性装载到一个类对象中,不受外界的影响,比如:洗衣机就是对洗衣服功能,甩干功能,漂洗功能等的封装,其功能不会受到外界的微波炉影响。 继承就是可以将类对象进行继承,派生类会继承基类的功能与属性,类似父与子的关系。比如水果和苹果,苹果就有水果的特性。
25 1
|
8天前
|
C++
【C++】从零开始认识多态(一)
面向对象技术(oop)的核心思想就是封装,继承和多态。通过之前的学习,我们了解了什么是封装,什么是继承。 封装就是对将一些属性装载到一个类对象中,不受外界的影响,比如:洗衣机就是对洗衣服功能,甩干功能,漂洗功能等的封装,其功能不会受到外界的微波炉影响。 继承就是可以将类对象进行继承,派生类会继承基类的功能与属性,类似父与子的关系。比如水果和苹果,苹果就有水果的特性。
30 4
|
17小时前
|
Serverless C++
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
|
1天前
|
存储 设计模式 编译器
【C++】继承和多态常见的问题
【C++】继承和多态常见的问题
|
1天前
|
编译器 C++
【C++】多态 -- 详解(下)
【C++】多态 -- 详解(下)
|
1天前
|
编译器 Linux C++
【C++】多态 -- 详解(上)
【C++】多态 -- 详解(上)
|
3天前
|
C++ 开发者
C++程序中利用虚函数实现动态多态性
C++程序中利用虚函数实现动态多态性
11 2
|
6天前
|
C++
C++|多态性与虚函数(2)|虚析构函数|重载函数|纯虚函数|抽象类
C++|多态性与虚函数(2)|虚析构函数|重载函数|纯虚函数|抽象类
|
6天前
|
存储 安全 C语言
C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数
C++|多态性与虚函数(1)功能绑定|向上转换类型|虚函数
|
8天前
|
C++ 编译器 存储