引述自: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 }