深入探索C++对象模型(Inside the C++ object model) -- 摘阅笔记(关于对象 - esp 1)
Object Lessons 关于对象
在C语言中,“数据”和“处理数据的操作(函数)”是分开声明的,也就是说 ,语言本身并没有支持“数据和函数”之间的关联性。把这种程序方法称为程序性(procedural),由一组“分布在各个以功能为导向的函数中”的算法所驱动,它们处理的是共同的外部数据。
1 typedef struct point3d 2 { 3 float x; 4 float y; 5 float z; 6 7 }Point3d; 8 9 //打印一个Point3d,就需要定义一个这样的函数 10 void Point3d_print(const Point3d *pd) 11 { 12 printf("(%g, %g, %g)", pd->x, pd->y, pd->z); 13 } 14 //为了效率高点,可以定义成宏 15 #define Point3d_print( pd ) \ 16 printf("(%g, %g, %g)", pd->x, pd->y, pd->z); 17 18 //更直接的是直接在一个程序中完成操作 19 void my_foo() 20 { 21 Point3d *pd = get_a_point(); 22 .... 23 /* 直接打印出 point .... */ 24 printf("(%g, %g, %g)", pd->x, pd->y, pd->z); 25 } 26 27 //对于某个点的坐标可以直接存取 28 Point3d pt; 29 pt.x = 0.0; 30 // 或者直接定一个处理宏 31 #define X(p, xval) (p.x) = (xval) 32 ... 33 X(pt, 0.0);
在C++中, Point3d采用“抽象数据类型(abstract data type, ADT)”来实现:
1 class Point3d 2 { 3 friend ostream& operator<<(ostream &os, const Point3d &pt); 4 public: 5 Point3d(float x = 0.0, float y = 0.0, float z = 0.0) 6 :_x(x), _y(y), _z(z){} 7 8 float x() const { return _x; } 9 float y() const { return _y; } 10 float z() const { return _z; } 11 12 void x(float xval ) { _x = xval; } 13 void y(float yval ) { _y = yval; } 14 void z(float zval ) { _z = zval; } 15 16 private: 17 float _x; 18 float _y; 19 float _z; 20 }; 21 inline ostream& operator<<(ostream &os, const Point3d &pt) 22 { 23 os << "(" << pt.x() << "," << pt.y() << "," << pt.z() << ")"; 24 };
或者一个双层或者三层clasa层结构完成
1 class Point { 2 public: 3 Point(float x = 0.0): _x(x) {} 4 5 float x() const { return _x; } 6 7 void x(float xval) { _x = xval; } 8 protected; 9 float _x; 10 }; 11 12 class Point2d : public Point 13 { 14 public: 15 Point2d(float x = 0.0, float y = 0.0) 16 :Point(x), _y(y) {} 17 18 float y() { return _y; } 19 20 void y(float yval) { _y = yval; } 21 protected: 22 float _y; 23 }; 24 25 class Point3d: public Point2d 26 { 27 public: 28 Point3d(float x = 0.0, float y = 0.0, float z = 0.0) 29 : Point2d(x, y), _z(z) {} 30 31 float z() { return _z; } 32 33 void z( float zval) { _z = zval; } 34 protected: 35 float _z; 36 } 37 38 template< class T> 39 class Point3d 40 { 41 public: 42 Point3d(T x = 0.0, T y = 0.0, T z = 0.0) 43 : _x(x), _y(y),_z(z) {} 44 45 T x() const { return _x; } 46 T y() const { return _y; } 47 T z() const { return _z; } 48 49 void x(T xval ) { _x = xval; } 50 void y(T yval ) { _y = yval; } 51 void z(T zval ) { _z = zval; } 52 53 private: 54 T _x, _y, _z; 55 }; 56 57 template<class T, int dim> 58 class Point 59 { 60 public: 61 Point(); 62 Point(T coords[dim]) { 63 for (int index = 0; index < dim; index++) 64 _coords[index] = coords[index]; 65 } 66 67 T& operator[] (int index){ 68 assert(index < dim && index >= 0); 69 return _coords[index]; 70 } 71 72 T operator[] (index) const { 73 assert(index < dim && index >= 0); 74 return _coords[index]; 75 } 76 77 // ... etc 78 private: 79 T _coords[dim]; 80 }; 81 82 inline 83 template <class T, int dim> 84 ostream & operator<<(ostream &os, const Point<T, dim> &pt) 85 { 86 os << "("; 87 for (int ix = 0; ix < dim - 1; ix++) 88 os << pt[ix] << ", "; 89 os << pt[dim - 1]; 90 os << ")"; 91 }
从软件工程的眼光来看,为什么“一个ADT或class hierarchy的数据封装”比“在C程序中程序性地使用全局数据”好。
加上封装后的布局成本(layout costs for adding Encapsulation)
C++在布局以及存取时间上主要的额外负担是由virtual引起的, 包括;
-
Virtual function 机制,用以支持一个有效的“执行期绑定”(runtime binding)
-
Virtual base class 用以实现“多次出现在继承体系中的base class, 有一个单一而被共享的实例“
-
多重继承下的额外负担, 发生在“一个derived class 和其第二或后继之后base class 的转换”之间。
一般,没有什么天生的理由说C++程序一定比其C程序庞大或迟缓。