虚函数,虚继承(以及内存分布,解决二义性问题)

虚函数
    虚函数的存在说明了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;
}
 
 

 假如没有虚继承的话
 
 
 
 
原文地址:https://www.cnblogs.com/Tempt/p/9987535.html