重温《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!

时间: 2024-11-24 06:14:56

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

Inside the C++ Object Model | Object Lessons

1. 加了封装后的布局存取成本(Layout Costs for Adding Encapsulation) 虚函数机制:用于支持有效率的执行期绑定 虚基类机制:实现在继承中避免重复继承. 2. The C++ Object Model pointer-to-member:避免了成员类型不同所需空间不同的问题,对象的成员是以 slot 的索引值来寻址 data member table: member function table: virtual table(vtbl):每个对象有一个指针指(

重温《Inside The C++ Object Model》(2) --Default-Constructor的建构操作

//constructor/non-constructor的区别 class Foo { public: //Foo():val(0),next(NULL) {} int val; Foo *next; }; void foo_bar() { Foo bar; if ( bar.val && bar.next ) { cout << bar.val << endl; printf("%p\n", bar.next); cout <<

inside the C++ Object model总结

一. 关于对象 1.内联函数:能够除去函数调用的开支,每一处内联函数的调用都是代码的复制.这是一种空间换取时间的做法,若函数代码量大或者有循环的情况下,不宜内联(这件事有些编译器会自动帮你做).在类中若直接将函数实现写在类体内,默认内联.如果函数因其复杂度或构建等问题被判断为不能成为inline函数,它将被转化为一个static函数.如果一个inline函数被调用太多次的话,会产生大量的扩展码,使程序大小暴涨. 2.C++对象模型: 3.组合,而非继承是把C和C++结合的唯一可行方法. 4.C+

Inside The C++ Object Model(一)

============================================================================1-1. 关键字struct和class的一点区别:(1)struct内部默认public属性,class内部成员默认private属性:(2)template中只能使用class来抽象类型参数,不能使用struct,template并不打算和C兼容. 1-2. C程序员有时会把单一元素的数组放在一个struct的尾端,于是每个struct ob

Inside The C++ Object Model(三)

============================================================================3-0. 类所占的内存大小受到三个因素的影响:(1)语言本身所造成的额外负担(Virtual base classes):(2)编译器对于特殊情况所提供的优化处理(空基类优化):(3)Alignment的限制(对齐):注:Empty Virtual base class提供一个Virtual interface,没有定义任何数据,某些编译器对此提

Inside The C++ Object Model(四)

============================================================================4-1. Member 的各种调用方式静态成员函数(static member functions,不属于对象,没有this指针)不能直接存取Nonstatic数据:同时不能被声明为const(const用于后置修饰函数时只用于限定成员函数,意味着将被修饰的成员函数的隐式参数--this指针由原来的Class* const变为const Clas

Inside The C++ Object Model(二)

============================================================================2-0. 关键字explicit被引入C++,提供给程序员一种方法,使他们能够制止"单一参数的constructor"被当做一个conversion运算符. ============================================================================2-1.Default Co

Inside The C++ Object Model(五)

============================================================================5-0. 一般而言,class 的data member 应该被初始化,并且只在constructor中是在class 的其他member functions 中指定初值.其他任何操作都将破坏封装性质,是class 的维护和修改更加困难. 图片5-0: (1)纯虚拟函数的存在注:编译器不会在扩展derived class 的destructor时

《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记

转载:http://dsqiu.iteye.com/blog/1669614 第一章 关于对象 使用class封装之后的布局成本: class并没有增加成本,data members直接内含在每一个class object之中,就像C struct一样.而member functions虽然被包含在class的声明之内,但是不出现在Object之中.每一个non-inline function 只会产生一个函数实体.至于inline function则会在每一个调用使用的地方产生一个函数实体(在