zoukankan      html  css  js  c++  java
  • 基类与派生类,父类指针指向子类对象

    先看一段代码:

     1 #include<iostream>
     2 
     3 using namespace std;
     4 
     5 class Base{
     6 public:
     7     Base() { cout<<"Base Creted"<<endl; }
     8     ~Base() { cout<<"Base Destroyed"<<endl; }
     9 };
    10 
    11 class Derived: public Base {
    12 public:
    13     Derived() { cout<<"Derived Created"<<endl; }
    14     ~Derived() { cout<<"Derived Destroyed"<<endl; }
    15 };
    16 
    17 int main()
    18 {
    19     Base *pB = new Derived();
    20     delete pB;
    21     pB = NULL;
    22     return 0;
    23 }

    运行结果如下,情理之中,意料之内:

    C++创建对象的时候先创建基类部分,然后创建派生部分。析构的时候要反过来了,先释放子类部分,然后在释放父类部分。但是这里只释放了父类部分,没有释放派生类的部分。为什么呢?

    原因很明确:因为之类pB是基类指针,虽然指向的是派生类,只能调用自己的函数,我们是无法通过基类指针调用到子类的成员函数的(除非采用virtual,也就是迟绑定技术)。

    虚函数

    为了不造成内存泄漏,我们将上面代码改成:

    1 class Base{
    2 public:
    3     Base() { cout<<"Base Creted"<<endl; }
    4     virtual ~Base() { cout<<"Base Destroyed"<<endl; }   //virtual关键字很关键哦
    5 };

    运行结果正确了:

    和之前版本相比,基类的析构函数多了一个 virtual 关键字。这样就使得父类类型的指针可以调用子类的成员函数。虚拟函数就是为了对“如果你以一个基础类指针指向一个衍生类对象,那么通过该指针,你只能访问基础类定义的成员函数”这条规则反其道而行之的设计。如果你打算将某个类作为基类,那么一定要定义一个虚析构函数。

    虚函数通过动态绑定技术实现了C++的运行时的多态性。让我们可以通过基类的指针或者引用调用派生类的方法。C++中还有一个多态性是编译时的多态,通过模版实现。

    《Effective C++》条款 07 p40:为多态基类声明virtual析构函数。

    《Effective C++》条款 07 p44:

    • 带多态性质的base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数
    • Classes的设计目的如果不是作为base classes 使用,或不是为了具备多态性,就不该声明virtual析构函数。

    动态绑定的是怎么实现的?

    1、为每个含义虚函数的类创建一个虚函数表VTable,存到常量区,依次存放虚函数的地址。对于每个派生类来说,如果没有重写基类的虚函数,那么派生类的虚函数表中的函数地址还是基类的那个虚函数地址。

    2、为每个含有虚函数的对象创建一个指向VTable的指针VPtr,所以说同类对象的VPtr是一样的。

    3、当基类指针指向派生类时,放生了强制转换,基类的指针指向了派生类的VPtr,这样当pBase->func()时,就可以调用派生类的func()了。

    4、没有虚函数的类也就没有VTable表了,或者这个表为空。这样基类指针自然调用不到派生类的函数了。

    思考:

    为何要让父类指针指向派生类对象?

    我觉得是为了实现C++的多态性。比如简单工厂模式,一开始我们并不知道需要生产哪种产品,也就不知道返回的是什么类型的产品,此时只能用基类指针去指向返回值。除此之外还没想到其他的使用场景。

  • 相关阅读:
    Apache-Tomcat 和 Apache-Maven配置
    php版本CKFinder3.4.4自定义上传文件位置
    php版本CKEditor 4和CKFinder安装及配置
    windows10 卸载 Docker 和 DockerNAT
    faker php测试数据库生成2
    faker php测试数据库生成
    我的php.ini上传文件配置
    同一个网址电脑手机访问显示不同内容思路
    mysql where 条件中的字段有NULL值时的sql语句写法
    Chrome导出书签瘦身,去除ADD_DATE和ICON
  • 原文地址:https://www.cnblogs.com/howo/p/8531449.html
Copyright © 2011-2022 走看看