(GeekBand)C++面向对象浅谈

1.一个类的对象所占的内存空间

一个Class对象需要的内存空间主要包括以下三个部分:
1.非静态成员变量总合(静态变量不占用类的内存)
2.编译器作出的数据对齐处理
3.支持虚函数产生的虚指针(普通函数不占用类的内存)

举例分析:

1.空类
class Test
{...};

编译器会给空类创建一个1byte的空间,因此空类对象所占的额内存为一个字节。

2.只含有成员变量的类
class Complex
{
private: 
    int re;
    int im;
    static int number;
};

这时候类的对象的大小就变成了8bytes,因为有两个非静态成员变量。
而static变量在内存中始终占用相同的一块内存,因此在对象中占用内存。

class Complex
{
private: 
    char user;
    int re;
    int im;
    static int number;
};

这个类相对于上一个多了一个char变量,所有变量加起来为9bytes。
而为了内存对齐,需要进行扩展,因此最后结果是12bytes。

3.含有虚函数的类
class Test
{
public: 
    Test( ) {...}
    virtual ~Test( ) {...}
};

2.虚函数表解析

1.简介

C++中的虚函数的作用主要是实现了多态。
多态就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,是一种泛型技术。
泛型技术指试图使用不变的代码来实现可变的算法。

2.虚函数表

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。
在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。

假设有下面这个类:

class Base {
public:
    virtual void f( ) { cout << "Base::f" << endl; }
    virtual void g( ) { cout << "Base::g" << endl; }
    virtual void h( ) { cout << "Base::h" << endl; }
};

我们可以通过Base的实例来得到虚函数表。

    Base b;
    cout << "虚函数表地址:" << (int*)(&b) << endl;
    cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;

可得到:
虚函数表地址:0012FED4
虚函数表 — 第一个函数地址:0044F148

你可能感兴趣的:((GeekBand)C++面向对象浅谈)