如何用C语言实现面向对象

如何用C语言实现面向对象,第1张

可以通过以下方法实现面向对象

1、封装

封装就是把数据和方法打包到一个类里面。其实C语言编程者应该都已经接触过了,C 标准库 中的 fopen(), fclose(), fread(), fwrite()等函数的 *** 作对象就是 FILE。

数据内容就是 FILE,数据的读写 *** 作就是 fread()、fwrite(),fopen() 类比于构造函数,fclose() 就是析构函数。

2、继承

继承就是基于现有的一个类去定义一个新类,这样有助于重用代码,更好的组织代码。在 C 语言里面,去实现单继承也非常简单,只要把基类放到继承类的第一个数据成员的位置就行了。

例如,我们现在要创建一个 Rectangle 类,我们只要继承 Shape 类已经存在的属性和 *** 作,再添加不同于 Shape 的属性和 *** 作到 Rectangle 中。

3、多态 C++

语言实现多态就是使用虚函数。在 C 语言里面,也可以实现多态。 现在,我们又要增加一个圆形,并且在 Shape 要扩展功能,我们要增加 area() 和 draw() 函数。

但是 Shape 相当于抽象类,不知道怎么去计算自己的面积,更不知道怎么去画出来自己。而且,矩形和圆形的面积计算方式和几何图像也是不一样的。

4、虚表和虚指针

虚表(Virtual Table)是这个类所有虚函数的函数指针的集合。

虚指针(Virtual Pointer)是一个指向虚表的指针。这个虚指针必须存在于每个对象实例中,会被所有子类继承。

5、在构造函数中设置vptr

在每一个对象实例中,vptr 必须被初始化指向其 vtbl。最好的初始化位置就是在类的构造函数中。

事实上,在构造函数中,C++ 编译器隐式的创建了一个初始化的vptr。在 C 语言里面, 我们必须显示的初始化vptr。下面就展示一下,在 Shape 的构造函数里面,如何去初始化这个 vptr。

你应该补充一下面向对象编程的有关知识,一两句话很难解释清楚。敲完下面这段很累!

上个世纪90年代以前的程序设计主要采用的是结构化设计。那时的程序基本上就是一堆数据和函数的集合体。

比如,要计算圆的面积,就要有数据的定义:

float r //圆的半径

float s //圆的面积

还要有算法的定义:

float CalcArea() {...}

完成这一单一任务,似乎体现不出结构化编程的缺陷,但是对于一个稍微复杂一点的程序,结构化编程的弊端就暴露出来了,比如,除了要计算圆的面积,还要计算矩形的面积、三角形的面积、梯形的面积等等,甚至还要计算以r为半径球的体积、圆柱的体积、椎体的体积等等等等,那么你就会有大量的数据定义和函数定义,这些数据和函数被松散的组织在一起(数据和函数之间除了程序员的思维外几乎没有什么东西能将二者联系起来),即使是按字典一样的将函数归类,在使用过程中依然会面临种种问题:你有了圆的半径,但不知哪个函数是用来计算圆的面积的;或者知道了函数的名字,确不知道应当使用哪个数据;又或者,你取了三角形的变长却用了计算圆面积的函数……

造成麻烦的根源在于在结构化设计中数据和针对数据的函数之间缺乏必要的联系,而现实世界中的万事万物,其本身所具有的特征和它具有的行为之间是有必然联系的,比如人有足,可以直立行走;畜有蹄,可以四肢着地;而蛇无足无蹄,唯有匍地而行。足是人的特征,直立行走是人的行为,有‘足’才能‘直立行走’;蹄是畜牲的特征,靠四肢行走是畜牲的行为,有‘蹄’才有‘靠四肢行走’;无足无蹄是蛇的特征,匍地而行是蛇的行为。联系是客观世界的普遍规律,从这一观点出发,产生了面向对象的思想。

对象(Object)就是主观和客观存在的万事万物,对象包含属性和方法。属性就是对象所具有的特征(属性的表现形式是数据),方法就是对象的行为集合(方法的表现形式是函数)。比如,人被看作是一个‘对象’,足就是该对象的‘属性’(即数据),直立行走就是该对象的‘方法’(即函数)。通过‘对象’这一概念便将数据及针对该数据的函数联系起来。

对于计算圆的面积这项任务来说,圆就可以被看作是一个对象,半径r是圆才具有的属性,面积=πr²是计算圆的面积的特定方法。

再进一步,无论大圆还是小圆它都可以归类为圆形,也都具有圆的属性和方法。就像是某部电影里片尾的歌词:他大舅、他二舅都是他舅。。。因此,所有的圆形对象最终都可以归结为一'类',即‘圆形类’。大圆、小圆不过是该‘类’的两个特殊的个体,有个‘类’就很容易创造出无数的个体。类的观点就是面向对象程序设计的根本出发点。类的基本结构如下:

class 类名

{

数据类型 属性1

数据类型 属性2

……

数据类型 属性n

返回值类型 方法1(参数1, 参数2,...)//方法可能反馈一个结果,也可能不反馈

{……}

返回值类型 方法2(参数1, 参数2,...)

{……}

}

对于圆类来讲就是:

class Circle //Circle就是类名

{

private int radius//圆的属性(注:在C#中该项被称为字段,属性一词有别的含义)

public Circle(int r) //构造函数,用于定义:创建一个‘个体’对象时,对象初始状态是什么样子的

{

radius=r

}

public double Area() //圆的方法

{

return Math.PI*radius*radius

}

}

Circle c=new Circle(50) //调用圆形类的构造函数,创建一个半径为50的圆形的‘个体’对象

double areaOfCircle=c.Area() //c.Area()指的是调用对象c所具有的方法Area()来计算对象c的面积。中间的那个圆点用来访问对象的属性:【对象.属性】和调用对象的方法:【对象.方法】。

凡是需要计算圆的面积的地方,如main()函数或其它函数内,都可以使用最后那部分代码。

java作为互联网编程中使用范围最广泛的编程语言之一,我们有许多的知识是需要掌握学习的,今天java课程培训机构http://www.kmbdqn.cn/就给大家分析讲解一下java面向对象的编程方法有哪些。

常用的创建对象的模式有以下几种:

一.工厂模式

工厂模式抽象了具体对象的过程,用函数来封装以特ing接口创建对象的细节。

如下:

functioncreateAnimal(name,age){

varo=newObject()

o.name=name

o.age=age

o.sayName=function(){

alert(this.name)

}

returno

}

varcat=createAnimal("cat",12)

vardog=createAnimal("dog",3)

工厂模式虽然解决了创建多个相似兑现过的问题,但是却没有解决对象识别的问题。

二.构造函数模式

构造函数模式可以创建特定类型的对象。

functionAnimal(name,age){

this.name=name

this.age=age

this.sayName=function(){

alert(this.name)

}

}

varcat=newAnimal("cat",12)

vardog=newAnimal("dog",3)

可以使用对象的constructor属性或instanceof *** 作符来标识对象类型。

cat.constructor==Animal//true

catinstanceofAnimal//true

三.原型模式

每个函数都有一个prototype(原型)属性。这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。

使用原型对象的好处是,可以让所有对象实例共享它所包含的属性和方法。

functionAnimal(){}

Animal.prototype.name="animal"

Animal.prototype.age=1

Animal.prototype.sayName=function(){

alert(this.name)

}

vartest1=newAnimal()

test1.sayName()//"animal"

vartest2=newAnimal()

test2.sayName()//"animal"

alert(test1.sayName===test2.sayName)//true

或者:

functionAnimal(){}

Animal.prototype={

constructor:Animal,

name:"animal",

age:1,

sayName:function(){

alert(this.name)

}

}

原型中所有属性是被很多实例共享的,通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。但是,对于包含引用类型值的属性来说,问题就比较明显了。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11938610.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存