zoukankan      html  css  js  c++  java
  • 虚函数,虚继承(以及内存分布,解决二义性问题)

    虚函数
        虚函数的存在说明了C++的多态性
    实现的方法:父类指针指向了子类对象,调用虚函数,调用的是子类的虚函数
    如果没有虚函数,那么无论用父类指针怎么调用函数,会永远调用父类函数,因为这是静态联编)
    只有通过基类指针或者引用去调用虚函数,才会引发动态联编
    基类中的虚函数,在派生类中也是虚函数,即使没有virtual
     
       什么函数不能是虚函数(只有成员函数才能是虚函数)
        1.    构造函数        因为虚函数是对象创建出来后动态联编的,而对象的创建是通过构造函数,这里没有调用构造函数创建对象,就让构造函数为虚函数,在逻辑上明显不符
        2.    内联函数        因为是动态联编,内联函数是代码替换,代码膨胀,代码替换是静态联编
        3.    静态函数        静态函数不属于任何对象,所以无法使用对象去调用静态函数
        4.    友元函数        上面说过,只有成员函数才能是虚函数,友元函数是普通的函数,不是成员函数
     
    在这里析构函数可以是虚函数,原因是:
            基类指针指向子类对象,是多态常见的做法,那么delete基类指针去释放空间,也是常见的做法,但是在这里,delete基类指针只会调用
    基类的析构函数,子类的析构函数不会被调用,所以子类的内存可能会发生泄露,所以在这里,将基类的析构函数,设置为虚函数,delete基类指针时,会同时调用派生类的析构函数
     
    纯虚函数
    纯虚函数的声明必须出现在类内,我们也可以为纯虚函数提供定义,不过函数体必须定义在类的外部,也就是说
        我们不能再类的内部为一个 =0 的函数提供函数体
     
    抽象类
    含有纯虚函数的类是抽象基类,抽象基类负责定义接口,而后续的其他类可以覆盖接口,
    我们不能创建出一个抽象基类的对象
    派生类中必须实现基类中的纯虚函数,否则他仍将被看做为一个抽象类
     
     
     
    ----------------------------------------------------------------------------------------------------------------------------------------------------------------
    内存分布
     
    1 普通的C++对象内存占用情况是什么样的?
    一般简单情况,比较好推断,但是下面的情况,就不好推断了
     
    <wiz_code_mirror>
    class A
    {
    public:
        int m;
        double n;
        char a;
    };
    class B
    {
    public:
        int m;
        char a;
        double n;
    };
    int _tmain(int argc, _TCHAR* argv[]) {
        printf("%d
    ", sizeof(A));
        printf("%d
    ", sizeof(B));
        return 0;
    }
     
     
    输出的结果是:
    24
    16
    同样的成员,但是占用内存的大小不同,是什么原因呢?
    内存排布的规则是:
    1 有一个默认的对齐数,假设是A。
    2 排布每一个成员的时候,成员大小和A取其中的最小值,假设是N。
    3 成员起始偏移,应该为N的整数倍。
    4 最终对象的大小还应该是每一个N中最大值的整数倍。
    根据以上规则分析class A
    0~3      int m;
    4~7      空出来了
    8~15    double n;
    16        char a;
    17~23  为了规则4整体对齐空出来的。
    根据以上规则分析class B
    0~3      int     m;
    4          char  a;
    5~7      空出来的
    8~15    double n;
    所以说A的大小是24字节,B的大小是16字节。
    在继承关系中,依然符合上面的规则:
     
    <wiz_code_mirror>
     
     
     
     
     
    class A
    {
    public:
        int m;
        double n;
        char a;
    };
    class B :virtual public A
    {
    public:
        int o;
        int p;
        int q;
    };
    int _tmain(int argc, _TCHAR* argv[]) {
        printf("%d
    ", sizeof(B));
        return 0;
    }
     
     
    A是24,B是12,但是合在了一起大小却是40.
    下面我们来考虑虚继承的情况
    当一个类虚继承自另一个类的时候:
     

    class A
    {
    public:
        A():l(0),m(1),n(2)
        {
        }
    public:
        int l;
        int m;
        int n;
     
    };
    class B :virtual public A
    {
    public:
        B() :o(3), p(4), q(5)
        {
        }
    public:
        int o;
        int p;
        int q;
    };
     
    效果就是多了一个虚基类表
     当多个虚继承的时候,如下面的代码:
     

    #include <iostream>
    using std::cout;
    using std::endl;
    class A
    {
    public:
        A():l(0),m(1),n(2)
        {
        }
    public:
        int l;
        int m;
        int n;
     
    };
    class B :virtual public A
    {
    public:
        B() :o(3), p(4), q(5)
        {
        }
    public:
        int o;
        int p;
        int q;
    };
    class C :virtual public A
    {
    public:
        C() :x(6), y(7), z(8)
        {
        }
    public:
        int x;
        int y;
        int z;
    };
    class D:public B, public C
    {
    public:
        D() :a(9), b(10)
        {
        }
    public:
        int a;
        int b;
    };
    int _tmain(int argc, _TCHAR* argv[]) {
        D obj;
        printf("%d
    ", sizeof(D));
        return 0;
    }
     
     

     假如没有虚继承的话
     
     
     
     
  • 相关阅读:
    弹出框 popover.js
    模态框 modal.js
    关于css阴影和浮动
    css文件分类
    按钮效果
    二级导航栏
    在CSS3中,可以利用transform功能来实现文字或图像的旋转、缩放、倾斜、移动这四种类型的变形处理
    CSS3背景定位 background-origin
    什么是优雅降级和渐进增强
    居中
  • 原文地址:https://www.cnblogs.com/Tempt/p/9987535.html
Copyright © 2011-2022 走看看