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     }   

 

你可能感兴趣的:(C++)