Loading

深入探索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)

增加封装后,布局成本增加了多少?答案是 class Point3d并没有增加多少成本。三个data membeers 直接内含在一个class objects之中,就像C struct 的情况一样。而member function虽然含在class的声明之内,却不出现在object之中。 每一个non-inline member function只会诞生一个函数实例。至于每一个“拥有零个或一个定义的”的inline function 则会在其每一个使用者(模块)身上产生一个函数实例。

C++在布局以及存取时间上主要的额外负担是由virtual引起的, 包括;

  • Virtual function 机制,用以支持一个有效的“执行期绑定”(runtime binding)

  • Virtual base class 用以实现“多次出现在继承体系中的base class, 有一个单一而被共享的实例“

  • 多重继承下的额外负担, 发生在“一个derived class 和其第二或后继之后base class 的转换”之间。

一般,没有什么天生的理由说C++程序一定比其C程序庞大或迟缓。

 

posted @ 2020-07-25 10:14  RainDavi  阅读(231)  评论(0编辑  收藏  举报