c语言实现面向对象OOC
这种问题比较锻炼思维,同时考察c和c++的掌握程度。如果你遇到过类似问题,此题意义自不必说。如果用c实现c++,主要解决如何实现封装,继承和多态三大问题,本文分两块说。
1、封装
// Example class A contains regular and
// static member variables and methods. class A
{
private:
int m_x;
static int g_y;
int m_z; // Should be invoked when the object ends
void InformEnd(); public:
A(int x);
~A();
void UpdateX(int newX);
static void UpdateY(int newY);
}; // Initialization of the static variable
int A::g_y = ; // The non-static member variables
// are initialized in the constructor
A::A(int x)
{
m_x = x;
m_z = ;
} // Destructor invokes a private variable
A::~A()
{
InformEnd();
} // UpdateX checks the value of X against a static variable before updating the value
void A::UpdateX(int newX)
{
if (g_y != && m_x < newX)
{
m_x = newX;
}
} // Unconditional update of static variable m_y
void A::UpdateY(int newY)
{
g_y = newY;
} main()
{
// Create a object on the heap
A *pA = new A(); // Create an object on the stack
A a(); // Example of an access via a pointer
pA->UpdateX(); // Example of a direct access
a.UpdateX(); // Example of static method call
A::UpdateY(); // Deleting the object
delete pA;
}
/*
This code maps from the C++ code to the equivalent C code.
Mapping of the following entities is covered:
- classes - methods
- this pointer - member variables
- constructors - static methods
- destructors - static variables
*/ #include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef int BOOLEAN; /*
Structure A represents the class A. Only the non-static member
variables are present in the structure
*/
struct A
{
int m_x;
int m_z;
}; /* Notice that g_y is not a part of struct A. Its a separate global variable. */
int g_y = ; /*
Prototype for the InformEnd method. The C++ version of this method
did not have any parameters but the C mapped function needs the this
pointer to obtain the address of the object. Note that all non-static
methods in the C++ code would map to a C function the additional this
pointer as the first parameter.
*/
void InformEnd(A *this_ptr); /*
The constructor maps to function with the this pointer and the size of the
structure as parameters. this_ptr passed to the constructor is NULL when
the operator new is used to create the object. this_ptr contains a valid
pointer if the memory for the object to be constructed is already
allocated. (e.g. local variable or part of another structure.)
*/
A *A_Constructor(A *this_ptr, int x)
{
/*Check if memory has been allocated for struct A. */
if (this_ptr == NULL)
{
/*Allocate memory of size A. */
this_ptr = (A *) malloc(sizeof(A));
} /* Once the memory has been allocated for A, initialise members of A. */
if (this_ptr)
{
this_ptr->m_x = x;
this_ptr->m_z = ;
}
return this_ptr;
} /*
The following function is equivalent to a destructor. The this
pointer and a dynamic flag are passed as the two parameters to
this function. The dynamic flag is set to true if the object is
being deleted using the delete operator.
*/
void A_Destructor(A *this_ptr, BOOLEAN dynamic)
{
InformEnd(this_ptr); /* If the memory was dynamically allocated for A, explicitly free it. */
if (dynamic)
{
free(this_ptr);
}
} /*
A pointer this is passed as first argument. All member variables
in the code will be accessed through an indirecion from the this
pointer. Notice that static variables are accessed directly as
they do not belong to any instance.
*/
void A_UpdateX(A *this_ptr, int newX)
{
if (g_y != && this_ptr->m_x < newX)
{
this_ptr->m_x = newX;
}
} /*
Notice that this is not passed here. This is so because
A_UpdateY is a static function. This function can only access
other static functions and static or global variables. This
function cannot access any member variables or methods of class A
as a static function does not correspond to an instance.
*/
void A_UpdateY(int newY)
{
g_y = newY;
} main()
{
/*
Dynamically allocate memory by passing NULL in this arguement.
Also initialize members of struct pointed to by pA.
*/
A *pA = A_Constructor(NULL, ); /* Define local variable a of type struct A. */
A a; /*
Initialize members of struct variable a. Note that the
constructor is called with the address of the object as
a has been pre-allocated on the stack.
*/
A_Constructor(&a, ); /*
Method invocations in C++ are handled by calling the
corresponding C functions with the object pointer.
*/
A_UpdateX(pA, );
A_UpdateX(&a, ); /* UpdateY is a static method, so object pointer is not passed */
A_UpdateY(); /*
Delete memory pointed to by pA (explicit delete in
original code).
*/
A_Destructor(pA, TRUE); /*
Since memory was allocated on the stack for local struct
variable a, it will be deallocated when a goes out of scope.
The destructor will also be invoked. Notice that dynamic flag
is set to false so that the destructor does not try to
free memory.
*/
A_Destructor(&a, FALSE);
}
2、继承/多态
// A typical example of inheritance and virtual function use.
// We would be mapping this code to equivalent C. // Prototype graphics library function to draw a circle
void glib_draw_circle (int x, int y, int radius); // Shape base class declaration
class Shape
{
protected:
int m_x; // X coordinate
int m_y; // Y coordinate public:
// Pure virtual function for drawing
virtual void Draw() = ; // A regular virtual function
virtual void MoveTo(int newX, int newY); // Regular method, not overridable.
void Erase(); // Constructor for Shape
Shape(int x, int y); // Virtual destructor for Shape
virtual ~Shape();
}; // Circle class declaration
class Circle : public Shape
{
private:
int m_radius; // Radius of the circle public:
// Override to draw a circle
virtual void Draw(); // Constructor for Circle
Circle(int x, int y, int radius); // Destructor for Circle
virtual ~Circle();
}; // Shape constructor implementation
Shape::Shape(int x, int y)
{
m_x = x;
m_y = y;
} // Shape destructor implementation
Shape::~Shape()
{
//...
} // Circle constructor implementation
Circle::Circle(int x, int y, int radius) : Shape (x, y)
{
m_radius = radius;
} // Circle destructor implementation
Circle::~Circle()
{
//...
} // Circle override of the pure virtual Draw method.
void Circle::Draw()
{
glib_draw_circle(m_x, m_y, m_radius);
} main()
{
// Define a circle with a center at (50,100) and a radius of 25
Shape *pShape = new Circle(, , ); // Define a circle with a center at (5,5) and a radius of 2
Circle aCircle(,, ); // Various operations on a Circle via a Shape pointer
pShape->Draw();
pShape->MoveTo(, );
pShape->Erase();
delete pShape; // Invoking the Draw method directly
aCircle.Draw();
} /*
C code
The following code maps the C++ code for the Shape and Circle classes
to C code.
*/ #include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef int BOOLEAN; /*
Error handler used to stuff dummy VTable
entries. This is covered later.
*/
void pure_virtual_called_error_handler(); /* Prototype graphics library function to draw a circle */
void glib_draw_circle (int x, int y, int radius); typedef void (*VirtualFunctionPointer)(...); /*
VTable structure used by the compiler to keep
track of the virtual functions associated with a class.
There is one instance of a VTable for every class
containing virtual functions. All instances of
a given class point to the same VTable.
*/
struct VTable
{
/*
d and i fields are used when multiple inheritance and virtual
base classes are involved. We will be ignoring them for this
discussion.
*/
int d;
int i; /*
A function pointer to the virtual function to be called is
stored here.
*/
VirtualFunctionPointer pFunc;
}; /*
The Shape class maps into the Shape structure in C. All
the member variables present in the class are included
as structure elements. Since Shape contains a virtual
function, a pointer to the VTable has also been added.
*/ struct Shape
{
int m_x;
int m_y; /*
The C++ compiler inserts an extra pointer to a vtable which
will keep a function pointer to the virtual function that
should be called.
*/
VTable *pVTable;
}; /*
Function prototypes that correspond to the C++ methods
for the Shape class,
*/
Shape *Shape_Constructor(Shape *this_ptr, int x, int y);
void Shape_Destructor(Shape *this_ptr, bool dynamic);
void Shape_MoveTo(Shape *this_ptr, int newX, int newY);
void Shape_Erase(Shape *this_ptr); /*
The Shape vtable array contains entries for Draw and MoveTo
virtual functions. Notice that there is no entry for Erase,
as it is not virtual. Also, the first two fields for every
vtable entry are zero, these fields might have non zero
values with multiple inheritance, virtual base classes
A third entry has also been defined for the virtual destructor
*/ VTable VTableArrayForShape[] =
{
/*
Vtable entry virtual function Draw.
Since Draw is pure virtual, this entry
should never be invoked, so call error handler
*/
{ , , (VirtualFunctionPointer) pure_virtual_called_error_handler }, /*
This vtable entry invokes the base class's
MoveTo method.
*/
{ , , (VirtualFunctionPointer) Shape_MoveTo }, /* Entry for the virtual destructor */
{ , , (VirtualFunctionPointer) Shape_Destructor }
}; /*
The struct Circle maps to the Circle class in the C++ code.
The layout of the structure is:
- Member variables inherited from the the base class Shape.
- Vtable pointer for the class.
- Member variables added by the inheriting class Circle.
*/ struct Circle
{
/* Fields inherited from Shape */
int m_x;
int m_y;
VTable *pVTable; /* Fields added by Circle */
int m_radius;
}; /*
Function prototypes for methods in the Circle class.
*/ Circle *Circle_Constructor(Circle *this_ptr, int x, int y, int radius);
void Circle_Draw(Circle *this_ptr);
void Circle_Destructor(Circle *this_ptr, BOOLEAN dynamic); /* Vtable array for Circle */ VTable VTableArrayForCircle[] =
{
/*
Vtable entry virtual function Draw.
Circle_Draw method will be invoked when Shape's
Draw method is invoked
*/
{ , , (VirtualFunctionPointer) Circle_Draw }, /*
This vtable entry invokes the base class's
MoveTo method.
*/
{ , , (VirtualFunctionPointer) Shape_MoveTo }, /* Entry for the virtual destructor */
{ , , (VirtualFunctionPointer) Circle_Destructor }
}; Shape *Shape_Constructor(Shape *this_ptr, int x, int y)
{
/* Check if memory has been allocated for struct Shape. */
if (this_ptr == NULL)
{
/* Allocate memory of size Shape. */
this_ptr = (Shape *) malloc(sizeof(Shape));
} /*
Once the memory has been allocated for Shape,
initialise members of Shape.
*/
if (this_ptr)
{
/* Initialize the VTable pointer to point to shape */
this_ptr->pVTable = VTableArrayForShape;
this_ptr->m_x = x;
this_ptr->m_y = y;
} return this_ptr;
} void Shape_Destructor(Shape *this_ptr, BOOLEAN dynamic)
{
/*
Restore the VTable to that for Shape. This is
required so that the destructor does not invoke
a virtual function defined by a inheriting class.
(The base class destructor is invoked after inheriting
class actions have been completed. Thus it is not
safe to invoke the ineriting class methods from the
base class destructor)
*/
this_ptr->pVTable = VTableArrayForShape; /*...*/ /*
If the memory was dynamically allocated
for Shape, explicitly free it.
*/
if (dynamic)
{
free(this_ptr);
}
} Circle *Circle_Constructor(Circle *this_ptr, int x, int y, int radius)
{
/* Check if memory has been allocated for struct Circle. */
if (this_ptr == NULL)
{
/* Allocate memory of size Circle. */
this_ptr = (Circle *) malloc(sizeof(Circle));
} /*
Once the memory has been allocated for Circle,
initialise members of Circle.
*/
if (this_ptr)
{
/* Invoking the base class constructor */
Shape_Constructor((Shape *)this_ptr, x, y); /*
Noting that here pointer is to circle rather than shape
This overwriting the pointer set to shape in shape's constructor
*/
this_ptr->pVTable = VTableArrayForCircle; this_ptr->m_radius = radius;
}
return this_ptr;
} void Circle_Destructor(Circle *this_ptr, BOOLEAN dynamic)
{
/* Restore the VTable to that for Circle */
this_ptr->pVTable = VTableArrayForCircle; /*...*/ /*
Invoke the base class destructor after ineriting class
destructor actions have been completed. Also note that
that the dynamic flag is set to false so that the shape
destructor does not free any memory.
*/
Shape_Destructor((Shape *) this_ptr, FALSE); /*
If the memory was dynamically allocated
for Circle, explicitly free it.
*/
if (dynamic)
{
free(this_ptr);
}
} void Circle_Draw(Circle *this_ptr)
{
glib_draw_circle(this_ptr->m_x, this_ptr->m_y, this_ptr->m_radius);
} main()
{
/*
Dynamically allocate memory by passing NULL in this arguement.
Also initialse members of struct pointed to by pShape.
*/
Shape *pShape = (Shape *) Circle_Constructor(NULL, , , ); /* Define a local variable aCircle of type struct Circle. */
Circle aCircle; /* Initialise members of struct variable aCircle. */
Circle_Constructor(&aCircle, , , ); /*
Virtual function Draw is called for the shape pointer. The compiler
has allocated 0 offset array entry to the Draw virtual function.
This code corresponds to "pShape->Draw();"
*/
(pShape->pVTable[].pFunc)(pShape); /*
Virtual function MoveTo is called for the shape pointer. The compiler
has allocared 1 offset array entry to the MoveTo virtual function.
This code corresponds to "pShape->MoveTo(100, 100);"
*/
(pShape->pVTable[].pFunc)(pShape, , ); /*
The following code represents the Erase method. This method is
not virtual and it is only defined in the base class. Thus
the Shape_Erase C function is called.
*/
Shape_Erase(pShape); /* Delete memory pointed to by pShape (explicit delete in original code).
Since the destructor is declared virtual, the compiler has allocated
2 offset entry to the virtual destructor
This code corresponds to "delete pShape;".
*/
(pShape->pVTable[].pFunc)(pShape, TRUE); /*
The following code corresponds to aCircle.Draw().
Here the compiler can invoke the method directly instead of
going through the vtable, since the type of aCircle is fully
known. (This is very much compiler dependent. Dumb compilers will
still invoke the method through the vtable).
*/
Circle_Draw(&aCircle); /*
Since memory was allocated from the stack for local struct
variable aCircle, it will be deallocated when aCircle goes out of scope.
The destructor will also be invoked. Notice that dynamic flag is set to
false so that the destructor does not try to free memory. Again, the
compiler does not need to go through the vtable to invoke the destructor.
*/
Circle_Destructor(&aCircle, FALSE);
}
参考链接:c实现原文 http://www.eventhelix.com/realtimemantra/Object_Oriented/
ooc原则:http://www.eventhelix.com/realtimemantra/Object_Oriented/#.UyRbuY3HkqL
参考书籍:Object-oriented programming with ANSI-C
c语言实现面向对象OOC的更多相关文章
- [java学习笔记]java语言核心----面向对象之this关键字
一.this关键字 体现:当成员变量和函数的局部变量重名时,可以使用this关键字来区别:在构造函数中调用其它构造函数 原理: 代表的是当前对象. this就是所在函数 ...
- 第二十五节:Java语言基础-面向对象基础
面向对象 面向过程的代表主要是C语言,面向对象是相对面向过程而言,Java是面向对象的编程语言,面向过程是通过函数体现,面向过程主要是功能行为. 而对于面向对象而言,将功能封装到对象,所以面向对象是基 ...
- 如何使用C语言的面向对象
我们都知道,C++才是面向对象的语言,但是C语言是否能使用面向对象的功能? (1)继承性 typedef struct _parent { int data_parent; }Parent; type ...
- 比较分析C++、Java、Python、R语言的面向对象特征,这些特征如何实现的?有什么相同点?
一门课的课后题答案,在这里备份一下: 面向对象程序设计语言 – 比较分析C++.Java.Python.R语言的面向对象特征,这些特征如何实现的?有什么相同点? C++ 语言的面向对象特征: 对象模 ...
- 用C语言实现面向对象的开发
C语言的对象化模型 面向对象的特征主要包括: .封装,隐藏内部实现 .继承,复用现有代码 .多态,改写对象行为 采用C语言实现的关键是如何运用C语言本身的特性来实现上述面向对象的特征. 1.1 封装 ...
- 基于C语言的面向对象编程
嵌入式软件开发中,虽然很多的开发工具已经支持C++的开发,但是因为有时考虑运行效率和编程习惯,还是有很多人喜欢用C来开发嵌入式软件.Miro Samek说:"我在开发现场发现,很多嵌入式软件 ...
- 已看1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架、多线程(并发编程)、I/O(NIO)、Socket、JDBC、XML、反射等。[泛型]\
1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架.多线程(并发编程).I/O(NIO).Socket.JDBC.XML.反射等.[泛型]\1* ...
- luajit利用ffi结合C语言实现面向对象的封装库
luajit中.利用ffi能够嵌入C.眼下luajit的最新版是2.0.4,在这之前的版本号我还不清楚这个扩展库详细怎么样,只是在2.04中,真的非常爽. 既然是嵌入C代码.那么要说让lua支持 ...
- go语言之面向对象
Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...
随机推荐
- js中的换算小技巧
之前自己一直使用~~运算符来把‘112222’字符型的数值换算成整型的数值 但今天调试程序发现了一些问题 ~~'999'=>999 ~~'111111999'=>111111999 这些都 ...
- winform 开发心得~
winform自适应不同分辨率 不同dpi 1.窗体AutoScaleMode属性 使用None 2.自定义控件 AutoScaleMode 使用Inherit 3.所有控件窗体字体使用px为单位
- 2015年11月30日 spring初级知识讲解(一)装配Bean
序,Spring的依赖注入是学习spring的基础.IOC为控制反转,意思是需要的时候就由spring生成一个,而不是先生成再使用. 写在前面 Spring提供面向接口编程,面向接口编程与依赖注入协作 ...
- 更改vs自带的模板
路径:C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\ItemTemplatesCache\CSharp\Code\20 ...
- PHP团队 编码规范 & 代码样式风格规范
一.基本约定 1.源文件 (1).纯PHP代码源文件只使用 <?php 标签,省略关闭标签 ?> : (2).源文件中PHP代码的编码格式必须是无BOM的UTF-8格式: (3).使用 U ...
- 转:利用node压缩、合并js,css,图片
1.安装nodejs http://nodejs.org/ 2.安装各自的node package js我用的是UglifyJS github地址:https://github.com/mishoo/ ...
- JQuery实战手风琴-遁地龙卷风
(-1)写在前面 这个图片是我从网上下载的,向这位前辈致敬.图片资源在我的百度云盘里.http://pan.baidu.com/s/1nvfJHdZ 我用的是chrome49,JQuery3.0,案例 ...
- 【转】 GridView 72般绝技
说明:准备出一个系列,所谓精髓讲C#语言要点.这个系列没有先后顺序,不过尽量做到精.可能会不断增删整理,本系列最原始出处是csdn博客,谢谢关注. C#精髓 第四讲 GridView 72般绝技 作者 ...
- CSU 1328 近似回文词(2013湖南省程序设计竞赛A题)
题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1328 解题报告:中文题题意就不说了.还好数据不大,只有1000,枚举回文串的中心位置,然 ...
- iOS开发——UI基础-控制器,IBAction和IBOutlet,UIView
第一个ios程序 @interface ViewController : UIViewController @property(nonatomic, weak)IBOutlet UILabel *la ...