虚函数
虚函数的存在说明了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;
};
效果就是多了一个虚基类表
当多个虚继承的时候,如下面的代码:
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://img2018.cnblogs.com/blog/1541424/201811/1541424-20181120104201400-1285095445.png)
假如没有虚继承的话
![](https://img2018.cnblogs.com/blog/1541424/201811/1541424-20181120104218884-1400799880.png)