C 实现 C++继承多态 实例

引述自:http://www.eventhelix.com/realtimemantra/basics/ComparingCPPAndCPerformance2.htm#.UaG1Kdd3-fg

1
// A typical example of inheritance and virtual function use. 2 // We would be mapping this code to equivalent C. 3 4 // Prototype graphics library function to draw a circle 5 void glib_draw_circle (int x, int y, int radius); 6 7 // Shape base class declaration 8 class Shape 9 { 10 protected: 11 int m_x; // X coordinate 12 int m_y; // Y coordinate 13 14 public: 15 // Pure virtual function for drawing 16 virtual void Draw() = 0; 17 18 // A regular virtual function 19 virtual void MoveTo(int newX, int newY); 20 21 // Regular method, not overridable. 22 void Erase(); 23 24 // Constructor for Shape 25 Shape(int x, int y); 26 27 // Virtual destructor for Shape 28 virtual ~Shape(); 29 }; 30 31 // Circle class declaration 32 class Circle : public Shape 33 { 34 private: 35 int m_radius; // Radius of the circle 36 37 public: 38 // Override to draw a circle 39 virtual void Draw(); 40 41 // Constructor for Circle 42 Circle(int x, int y, int radius); 43 44 // Destructor for Circle 45 virtual ~Circle(); 46 }; 47 48 // Shape constructor implementation 49 Shape::Shape(int x, int y) 50 { 51 m_x = x; 52 m_y = y; 53 } 54 55 // Shape destructor implementation 56 Shape::~Shape() 57 { 58 //... 59 } 60 61 // Circle constructor implementation 62 Circle::Circle(int x, int y, int radius) : Shape (x, y) 63 { 64 m_radius = radius; 65 } 66 67 // Circle destructor implementation 68 Circle::~Circle() 69 { 70 //... 71 } 72 73 // Circle override of the pure virtual Draw method. 74 void Circle::Draw() 75 { 76 glib_draw_circle(m_x, m_y, m_radius); 77 } 78 79 main() 80 { 81 // Define a circle with a center at (50,100) and a radius of 25 82 Shape *pShape = new Circle(50, 100, 25); 83 84 // Define a circle with a center at (5,5) and a radius of 2 85 Circle aCircle(5,5, 2); 86 87 // Various operations on a Circle via a Shape pointer 88 pShape->Draw(); 89 pShape->MoveTo(100, 100); 90 pShape->Erase(); 91 delete pShape; 92 93 // Invoking the Draw method directly 94 aCircle.Draw(); 95 }
  1     /*
  2     The following code maps the C++ code for the Shape and Circle classes
  3     to C code.
  4     */
  5      
  6     #include <stdio.h>
  7     #include <stdlib.h>
  8     #define TRUE 1
  9     #define FALSE 0
 10     typedef int BOOLEAN;
 11      
 12     /*
 13     Error handler used to stuff dummy VTable
 14     entries. This is covered later.
 15     */
 16     void pure_virtual_called_error_handler();
 17      
 18     /* Prototype graphics library function to draw a circle */
 19     void glib_draw_circle (int x, int y, int radius);
 20      
 21     typedef void (*VirtualFunctionPointer)(...);
 22      
 23     /*
 24     VTable structure used by the compiler to keep
 25     track of the virtual functions associated with a class.
 26     There is one instance of a VTable for every class
 27     containing virtual functions. All instances of
 28     a given class point to the same VTable.
 29     */
 30     struct VTable
 31     {
 32        /*
 33        d and i fields are used when multiple inheritance and virtual
 34        base classes are involved. We will be ignoring them for this
 35        discussion.
 36        */
 37        int d;
 38        int i;
 39      
 40        /*
 41        A function pointer to the virtual function to be called is
 42        stored here.
 43        */
 44        VirtualFunctionPointer pFunc;
 45     };
 46      
 47     /*
 48     The Shape class maps into the Shape structure in C. All
 49     the member variables present in the class are included
 50     as structure elements. Since Shape contains a virtual
 51     function, a pointer to the VTable has also been added.
 52     */
 53      
 54     struct Shape
 55     {
 56       int m_x;
 57       int m_y;
 58      
 59       /*
 60       The C++ compiler inserts an extra pointer to a vtable which
 61       will keep a function pointer to the virtual function that
 62       should be called.
 63       */
 64       VTable *pVTable;
 65     };
 66      
 67     /*
 68     Function prototypes that correspond to the C++ methods
 69     for the Shape class,
 70     */
 71     Shape *Shape_Constructor(Shape *this_ptr, int x, int y);
 72     void Shape_Destructor(Shape *this_ptr, bool dynamic);
 73     void Shape_MoveTo(Shape *this_ptr, int newX, int newY);
 74     void Shape_Erase(Shape *this_ptr);
 75      
 76     /*
 77     The Shape vtable array contains entries for Draw and MoveTo
 78     virtual functions. Notice that there is no entry for Erase,
 79     as it is not virtual. Also, the first two fields for every
 80     vtable entry are zero, these fields might have non zero
 81     values with multiple inheritance, virtual base classes
 82     A third entry has also been defined for the virtual destructor
 83     */
 84      
 85     VTable VTableArrayForShape[] =
 86     {
 87         /*
 88         Vtable entry virtual function Draw.
 89         Since Draw is pure virtual, this entry
 90         should never be invoked, so call error handler
 91         */
 92         { 0, 0, (VirtualFunctionPointer) pure_virtual_called_error_handler },
 93      
 94         /*
 95         This vtable entry invokes the base class's
 96         MoveTo method.
 97         */
 98         { 0, 0, (VirtualFunctionPointer) Shape_MoveTo },
 99      
100         /* Entry for the virtual destructor */
101         { 0, 0, (VirtualFunctionPointer) Shape_Destructor }
102     };
103      
104     /*
105     The struct Circle maps to the Circle class in the C++ code.
106     The layout of the structure is:
107     - Member variables inherited from the the base class Shape.
108     - Vtable pointer for the class.
109     - Member variables added by the inheriting class Circle.
110     */
111      
112     struct Circle
113     {
114        /* Fields inherited from Shape */
115        int m_x;
116        int m_y;
117        VTable *pVTable;
118      
119        /* Fields added by Circle */
120        int m_radius;
121     };
122      
123     /*
124     Function prototypes for methods in the Circle class.
125     */
126      
127     Circle *Circle_Constructor(Circle *this_ptr, int x, int y, int radius);
128     void Circle_Draw(Circle *this_ptr);
129     void Circle_Destructor(Circle *this_ptr, BOOLEAN dynamic);
130      
131     /* Vtable array for Circle */
132      
133     VTable VTableArrayForCircle[] =
134     {
135         /*
136         Vtable entry virtual function Draw.
137         Circle_Draw method will be invoked when Shape's
138         Draw method is invoked
139         */
140         { 0, 0, (VirtualFunctionPointer) Circle_Draw },
141      
142         /*
143         This vtable entry invokes the base class's
144         MoveTo method.
145         */
146         { 0, 0, (VirtualFunctionPointer) Shape_MoveTo },
147      
148         /* Entry for the virtual destructor */
149         { 0, 0, (VirtualFunctionPointer) Circle_Destructor }
150     };
151      
152     Shape *Shape_Constructor(Shape *this_ptr, int x, int y)
153     {
154       /* Check if memory has been allocated for struct Shape. */
155       if (this_ptr == NULL)
156       {
157         /* Allocate memory of size Shape. */
158         this_ptr = (Shape *) malloc(sizeof(Shape));
159       }
160      
161       /*
162       Once the memory has been allocated for Shape,
163       initialise members of Shape.
164       */
165       if (this_ptr)
166       {  
167         /* Initialize the VTable pointer to point to shape */
168         this_ptr->pVTable = VTableArrayForShape;
169         this_ptr->m_x = x;
170         this_ptr->m_y = y;
171       }
172      
173       return this_ptr;
174     }
175      
176     void Shape_Destructor(Shape *this_ptr, BOOLEAN dynamic)
177     {
178       /*
179       Restore the VTable to that for Shape. This is
180       required so that the destructor does not invoke
181       a virtual function defined by a inheriting class.
182       (The base class destructor is invoked after inheriting
183       class actions have been completed. Thus it is not
184       safe to invoke the ineriting class methods from the
185       base class destructor)
186       */
187       this_ptr->pVTable = VTableArrayForShape;
188      
189       /*...*/
190      
191       /*
192       If the memory was dynamically allocated
193       for Shape, explicitly free it.
194       */
195       if (dynamic)
196       {
197         free(this_ptr);
198       }
199     }
200      
201     Circle *Circle_Constructor(Circle *this_ptr, int x, int y, int radius)
202     {
203       /* Check if memory has been allocated for struct Circle. */
204       if (this_ptr == NULL)
205       {
206         /* Allocate memory of size Circle. */
207         this_ptr = (Circle *) malloc(sizeof(Circle));
208       }
209      
210       /*
211       Once the memory has been allocated for Circle,
212       initialise members of Circle.
213       */
214       if (this_ptr)
215       {
216           /* Invoking the base class constructor */
217           Shape_Constructor((Shape *)this_ptr, x, y);
218           this_ptr->pVTable = VTableArrayForCircle;
219      
220           this_ptr->m_radius = radius;
221       }
222       return this_ptr;
223     }
224      
225     void Circle_Destructor(Circle *this_ptr, BOOLEAN dynamic)
226     {
227       /* Restore the VTable to that for Circle */
228       this_ptr->pVTable = VTableArrayForCircle;
229      
230       /*...*/
231      
232       /*
233       Invoke the base class destructor after ineriting class
234       destructor actions have been completed. Also note that
235       that the dynamic flag is set to false so that the shape
236       destructor does not free any memory.
237       */
238       Shape_Destructor((Shape *) this_ptr, FALSE);
239      
240       /*
241       If the memory was dynamically allocated
242       for Circle, explicitly free it.
243       */
244       if (dynamic)
245       {
246         free(this_ptr);
247       }
248     }
249      
250     void Circle_Draw(Circle *this_ptr)
251     {
252        glib_draw_circle(this_ptr->m_x, this_ptr->m_y, this_ptr->m_radius);
253     }
254      
255     main()
256     {  
257       /*
258       Dynamically allocate memory by passing NULL in this arguement.
259       Also initialse members of struct pointed to by pShape.
260       */
261       Shape *pShape = (Shape *) Circle_Constructor(NULL, 50, 100, 25);
262      
263       /* Define a local variable aCircle of type struct Circle. */
264       Circle aCircle;
265      
266       /* Initialise members of struct variable aCircle. */
267       Circle_Constructor(&aCircle, 5, 5, 2);
268      
269       /*
270       Virtual function Draw is called for the shape pointer. The compiler
271       has allocated 0 offset array entry to the Draw virtual function.
272       This code corresponds to "pShape->Draw();"
273       */
274       (pShape->pVTable[0].pFunc)(pShape);
275      
276       /*
277       Virtual function MoveTo is called for the shape pointer. The compiler
278       has allocared 1 offset array entry to the MoveTo virtual function.
279       This code corresponds to "pShape->MoveTo(100, 100);"
280       */
281       (pShape->pVTable[1].pFunc)(pShape, 100, 100);
282      
283       /*
284       The following code represents the Erase method. This method is
285       not virtual and it is only defined in the base class. Thus
286       the Shape_Erase C function is called.
287       */
288       Shape_Erase(pShape);
289      
290       /* Delete memory pointed to by pShape (explicit delete in original code).
291       Since the destructor is declared virtual, the compiler has allocated
292       2 offset entry to the virtual destructor
293       This code corresponds to "delete pShape;".
294       */
295       (pShape->pVTable[2].pFunc)(pShape, TRUE);
296      
297       /*
298       The following code corresponds to aCircle.Draw().
299       Here the compiler can invoke the method directly instead of
300       going through the vtable, since the type of aCircle is fully
301       known. (This is very much compiler dependent. Dumb compilers will
302       still invoke the method through the vtable).
303       */
304       Circle_Draw(&aCircle);
305      
306       /*
307       Since memory was allocated from the stack for local struct
308       variable aCircle, it will be deallocated when aCircle goes out of scope.
309       The destructor will also be invoked. Notice that dynamic flag is set to
310       false so that the destructor does not try to free memory. Again, the
311       compiler does not need to go through the vtable to invoke the destructor.
312       */
313       Circle_Destructor(&aCircle, FALSE);
314     }   

 

posted on 2013-05-26 15:11  阿加  阅读(1029)  评论(0编辑  收藏  举报

导航