首页 > 代码库 > 重温《Inside The C++ Object Model》(1) --关于对象

重温《Inside The C++ Object Model》(1) --关于对象

C/C++ 编程风格

//1.C风格(结构化程序设计):数据和函数(操作)没有任何关联性
typedef struct Point3d
{
    float x;
    float y;
    float z;
} Point3d_t;

void
Point3d_print(const Point3d_t *pd)
{
    printf("%g, %g, %g\n", pd->x, pd->y, pd->z);
}

//2.基于对象(Object-Base):提供抽象数据类型(ADT)来支持封装
class Point3d
{
    friend ostream &operator<<(ostream &os, const Point3d &pt);
public:
    Point3d(float x = 0.0, float y = 0.0, float z = 0.0):
        _x(x), _y(y), _z(z) {}

    float x()
    {
        return _x;
    }
    float y()
    {
        return _y;
    }
    float z()
    {
        return _z;
    }

    void x(float xval)
    {
        _x = xval;
    }

    //etc...

private:
    float _x;
    float _y;
    float _z;
};

inline ostream &
operator<<(ostream &os, const Point3d &pt)
{
    return os << "( " << pt._x << ", " << pt._y << ", "
           << pt._z << " )";
}

//3.面向对象(Object-Oriented-Model):提供继承和多态
class Point
{
public:
    Point(float x = 0.0):
        _x(x) {}

    float x()
    {
        return _x;
    }

    void x(float xValue)
    {
        _x = xValue;
    }

protected:
    float _x;
};

class Point2d : public Point
{
public:
    Point2d(float x = 0.0, float y = 0.0):
        Point(x), _y(y) {}

    float y()
    {
        return _y;
    }
    void y(float yValue)
    {
        _y = yValue;
    }

protected:
    float _y;
};

class Point3d : public Point2d
{
    friend inline ostream &
    operator<<(ostream &os, const Point3d &pt);

public:
    Point3d(float x = 0.0, float y = 0.0, float z = 0.0):
        Point2d(x, y), _z(z) {}

    float z()
    {
        return _z;
    }
    void z(float zValue)
    {
        _z = zValue;
    }

private:
    float _z;
};

inline ostream &
operator<<(ostream &os, const Point3d &pt)
{
    return os << "( " << pt._x << ", " << pt._y << ", "
           << pt._z << " )";
}

//4.面向泛型:提供模板提供类型无关化的编程风格
//示例(1):仅提供类型参数化
template <typename Type>
class Point3d
{
public:
    Point3d(Type x = 0.0, Type y = 0.0, Type z = 0.0):
        _x(x), _y(y), _z(z) {}

    Type x()
    {
        return _x;
    }
    Type y()
    {
        return _y;
    }
    Type z()
    {
        return _z;
    }

    void x(const Type &xval)
    {
        _x = xval;
    }

    //etc...

private:
    Type _x;
    Type _y;
    Type _z;
};

//示例(2):同时提供类型和数目(int dim)参数化
template <typename Type, int dim>
class Point
{
public:
    Point() {}
    Point(Type coordes[dim])
    {
        for (int index = 0; index < dim; ++index)
        {
            _coordes[index] = coordes[index];
        }
    }

    const Type &operator[](int index) const
    {
        assert(index < dim && index >= 0);
        return _coordes[index];
    }

private:
    Type _coordes[dim];
};

template <typename Type, int dim>
inline ostream &operator<<(ostream &os, const Point< Type, dim > &pt)
{
    os << "( ";
    for (int i = 0; i < dim; ++i)
        os << pt[i] << ", ";
    os << ")";
    return os;
}

//测试
    int array[] = {11,12,333};
    Point<int, 3> point(array);
    cout << point << endl;
cout << point[2] << endl;

小结:C++加上封装的布局成本

(1)三个data-member[数据成员]直接内含在每一个class-object[对象]之中,如同C-Struct一样;

(2)Member-function虽然存在于class的声明中, 却不出现在object之中, 每一个non-inline member function[非inline的成员函数]只会诞生一个函数实体;

(3)而inline member function会在其每一个使用者身上产生一个函数实体.

 

C++对象模型

1.所有的数据成员(static 数据成员除外)存放在每一个对象之中;

2.[1]static 数据成员,[2]成员函数(无论是static/non-static)存放在所有对象之外;

3.对virtual-functions, 每一个对象都有一个vptr(指向一个vtbl(包含type_info object, virtual functions)).

技术分享


因此:内存中对象的大小

(1)其non-static data member 的总和大小

(2)加上任何alignment(内存对其)的需求而填补上去的空间[可能存在于members中间, 也可能存在于集合体边界];

(3)加上支持virtual[vptr]而由内部产生的任何额外负担.

//测试
class Point1
{
};

class Point2
{
private:
    int number;
};

class Point3
{
public:
    Point3(int _number = 0): number(_number) {}
    ~Point3() {}
    static void showCount()
    {
        std::cout << "Point3_count = " << Point3_count << std::endl;
    }

private:
    static int Point3_count;

private:
    int number;
};

class Point4
{
public:
    virtual ~Point4();

private:
    int number;
};

int main()
{
    cout << sizeof(Point1) << endl;
    cout << sizeof(Point2) << endl;
    cout << sizeof(Point3) << endl;
    cout << sizeof(Point4) << endl;
}

对象在内存中的布局

Derived Class 的Object 和 Pointer布局(如下图)

技术分享

(其实ZooAnimal subobject 的布局有些错误, string类型在现代C++中只占4个字节, 因此ZooAnimal subobject所占的内存空间仅有12字节, 而不是图中的16字节)

说明:

(1)pointer & reference 都只需一个字长(x86_32中为4个字节)的空间;

(2)派生类对象中:基类子对象与派生类子对象在内存中的位置是相邻的.

//测试
class ZooAnimal
{
public:
    ZooAnimal() {}
    virtual ~ZooAnimal() {}
    virtual void rotate() {}

protected:
    int loc;
    string name;
};

class Bear : public ZooAnimal
{
public:
    Bear() {}
    ~Bear() {}

    void rotate()
    {

    }

protected:
    enum Dances
    {
        //...
    };
    Dances dances_known;
    int cell_block;
};


int main()
{
    Bear b;
    ZooAnimal *pz = &b;
    Bear *pb = &b;

    cout << "Pointer..." << endl;
    cout << sizeof(pz) << endl;
    cout << sizeof(pb) << endl;

    cout << "\nObject..." << endl;
    cout << sizeof(*pz) << endl;
    cout << sizeof(*pb) << endl;

    cout << "\nClass..." << endl;
    cout << sizeof(ZooAnimal) << endl;
    cout << sizeof(Bear) << endl;
}

测试说明:

pb 所涵盖的地址包含了整个Bear Object, 而 pz只包含了Bear Object中的ZooAnimal SubObject!

重温《Inside The C++ Object Model》(1) --关于对象