{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism/",
  "atlas": "https://www.pystone.net/?node=cpp-virtual-function-polymorphism#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism.md",
  "context": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:cpp-virtual-function-polymorphism",
  "slug": "cpp-virtual-function-polymorphism",
  "title": "虚函数与多态",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "虚函数与多态",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "65bfd2ceb78150267a13265e0e265c5078f9e228462b6fe54838c4df912410df",
  "assets": [
    {
      "reference": "assets/0015 - 虚函数与多态__resource-001-62e99b69c530.png",
      "url": "/media/7d16278d7ceea3a9062c.png",
      "mediaType": "image/png",
      "contentHash": "7d16278d7ceea3a9062cf38c4e2f36c484004a4f736898347b9bcfc64daacf10",
      "byteLength": 39187,
      "width": 313,
      "height": 714
    }
  ],
  "headings": [
    {
      "depth": 1,
      "text": "虚函数与多态",
      "anchor": "虚函数与多态",
      "citation": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism/#%E8%99%9A%E5%87%BD%E6%95%B0%E4%B8%8E%E5%A4%9A%E6%80%81"
    },
    {
      "depth": 3,
      "text": "多态",
      "anchor": "多态",
      "citation": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism/#%E5%A4%9A%E6%80%81"
    },
    {
      "depth": 3,
      "text": "虚函数",
      "anchor": "虚函数",
      "citation": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism/#%E8%99%9A%E5%87%BD%E6%95%B0"
    },
    {
      "depth": 4,
      "text": "实现原理",
      "anchor": "实现原理",
      "citation": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism/#%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"
    },
    {
      "depth": 4,
      "text": "其他问题",
      "anchor": "其他问题",
      "citation": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism/#%E5%85%B6%E4%BB%96%E9%97%AE%E9%A2%98"
    },
    {
      "depth": 4,
      "text": "为何构造函数不能是虚函数",
      "anchor": "为何构造函数不能是虚函数",
      "citation": "https://www.pystone.net/notes/cpp-virtual-function-polymorphism/#%E4%B8%BA%E4%BD%95%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%B8%8D%E8%83%BD%E6%98%AF%E8%99%9A%E5%87%BD%E6%95%B0"
    }
  ],
  "claims": [],
  "outgoing": [],
  "incoming": [
    {
      "id": "note:programming-languages-and-runtimes",
      "title": "编程语言与运行时",
      "url": "https://www.pystone.net/notes/programming-languages-and-runtimes/",
      "atlas": "https://www.pystone.net/?node=programming-languages-and-runtimes#knowledge-atlas",
      "label": "编程语言与运行时",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "C++中的“虚函数与多态”导航项",
      "citation": "https://www.pystone.net/notes/programming-languages-and-runtimes/#c"
    }
  ],
  "contentMarkdown": "# 虚函数与多态\n\n﻿# 虚函数与多态\n\n> 创建时间：2020/3/20 0:49\n\n### 多态\n\n**多态** 是指在不同的条件下表现出不同的状态。\n编译期间多态：重载函数，根据参数列表的不同寻找合适的函数\n运行时多态：虚函数\n\n### 虚函数\n\n  * 纯虚函数：父类没有实现版本，完全交给子类，且必须实现。是虚函数再加上 = 0；\n  * 半虚函数：父类可以实现，子类需要重写\n\n>   * 抽象类是指包括至少一个纯虚函数的类。\n>\n\n> 以下函数不能作为虚函数\n>\n>   1. 友元函数，它不是类的成员函数\n>   2. 全局函数\n>   3. 静态成员函数，它没有this指针\n>   4. 构造函数，拷贝构造函数，以及赋值运算符重载\n>\n\n> 创建对象的过程：\n>  https://www.cnblogs.com/yulei0713/p/11326254.html\n\n#### 实现原理\n\n为每个类对象添加一个隐藏成员，保存了一个指向 **函数地址数组** 的 **指针** ，称为 **虚表指针** （vptr），这种数组成为 **虚函数表** （virtual function table, vtbl），即，每个类使用一个虚函数表，每个类对象用一个虚表指针。\n\n如果类中有N个虚函数，那么其虚函数表将有(N * 4)字节的大小。\n\n> 基类对象包含一个指针，该指针指向基类所有虚函数的地址表，派生类对象将包含一个指向独立地址表的指针，如果派生类提供了虚函数的新定义，该虚函数表将保存新函数的地址，如果派生类没有重新定义虚函数，该虚函数表将保存函数原始版本的地址。如果派生类定义了新的虚函数，则该函数的地址将被添加到虚函数表中，注意虚函数无论多少个都只需要在对象中添加一个虚函数表的地址。\n>  调用虚函数时，程序将查看存储在对象中的虚函数表地址，转向相应的虚函数表，使用类声明中定义的第几个虚函数，程序就使用数组的第几个函数地址，并执行该函数。\n\n![](assets/0015 - 虚函数与多态__resource-001-62e99b69c530.png)\n\n> **关于对象大小问题**\n>  有虚函数或虚继承的类实例化后的 **对象大小** 至少为4字节（确切的说是一个指针的字节数；说至少是因为还要加上其他非静态数据成员，还要考虑对齐问题）；没有虚函数和虚继承的类实例化后的对象大小至少为1字节（没有非静态数据成员的情况下也要有1个字节来记录它的地址）。\n\n#### 其他问题\n\n（1）当存在类继承并且析构函数中有必须要进行的操作时（如需要释放某些资源，或执行特定的函数）析构函数需要是虚函数，否则若使用父类指针指向子类对象，在delete时只会调用父类的析构函数，而不能调用子类的析构函数，从而造成内存泄露或达不到预期结果；\n（2）内联函数不能为虚函数：内联函数需要在编译阶段展开，而虚函数是运行时动态绑定的，编译时无法展开；\n（3）构造函数不能为虚函数：构造函数在进行调用时还不存在父类和子类的概念，父类只会调用父类的构造函数，子类调用子类的，因此不存在动态绑定的概念；但是构造函数中可以调用虚函数，不过并没有动态效果，只会调用本类中的对应函数；\n（4）静态成员函数不能为虚函数：静态成员函数是以类为单位的函数，与具体对象无关，虚函数是与对象动态绑定的。\n\n#### 为何构造函数不能是虚函数\n\n  1. 从存储空间角度：\n虚函数对应一个vtable，要占存储空间。如果构造函数是虚的，就需要通过 vtable来调用，可是对象还没有实例化，也就是内存空间还没有，无法找到vtable，所以构造函数不能是虚函数。\n  2. vbtl在构造函数调用后才建立，因而构造函数不可能成为虚函数\n"
}
