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!