c++ 返回一个对象_好奇了好久的「对象」,就这?

5ec9816121400f772cdac1f57f1d530b.png

作者 | 编程指北

来源 | 编程指北(ID:cs_dev)

别误会,今天要写的不是我对象,毕竟我还没有......

这篇文章主要是聊聊我对于编程语言中「对象」的一些简单认识,

4fc05f8abaacc738a4ac06a0d2a40c92.png

面向过程 VS 面向对象

为什么 C 叫面向过程(Procedure Oriented)的语言,而 Java、C++ 之类叫面向对象(Object Oriented)呢?

之前听到一个有趣的说法:

在 C 语言中我们是这样写代码的:

function_a(yyy);function_b(xxx);

从左往右看过去,最先看到的是函数,也就是 Procedure,故叫做 Procedure Oriented。

而在 Java 这类语言我们通常是这样的:

Worker worker = new Woker("小北");worker.touchFish("5分钟");worker.coding("1小时");

第一眼看到的就是一个个的对象,所以叫做面向对象 Object Oriented。

回到正题。在 C 语言中,数据和操作数据的函数是互相分开的,你并不知道数据和函数之间有什么关联,这在语言层面上是不支持的。

在 C 语言中,编程就是将一堆以功能为核心导向的函数进行组合,依次调用这些函数就可以了。

这就叫面向过程,其实和我们思考问题的方式是吻合的。比如要实现一个贪吃蛇游戏,那面向过程的设计思路就是首先分析问题的步骤:

  1. 开始游戏

  2. 随机生成食物

  3. 绘制画面

  4. 接收输入并改变方向

  5. 判断是否碰到墙壁和食物等

  6. ...

而用面向对象的思路则是:

首先,将整个游戏拆解为一个个的实体:蛇、食物、障碍物、规则系统、动画系统。

其次,分别去实现这些实体应该具有的功能(即成员函数),同时你还要考虑不同实体之间如何交互和传递消息。说白了就是调用关系和传参。

比如规则系统接收蛇、食物、障碍物作为参数,可以判定是否吃到食物或者碰到墙壁。

动画系统则可以接收蛇、食物、障碍物等作为参数,然后在屏幕上动态的显示出来。

这样做的好处是:可以利用面向对象有封装、继承、多态性的特性,设计出低耦合的系统,使系统更加灵活、更加易于维护。

好了,上面这段大概可以看做八股文。你分别用 C 和 Java/C++ 写过程序自然知道二者区别。不然我说再多的高内聚、低耦合也没啥用。

ab1c509420d4598a23d65584e24695d4.png

对象如何实现?

对象的就是由一堆的属性(成员变量)和一系列的方法(成员函数)组成。在讲这个之前,先补充说明一个函数指针。

我们都知道函数在 C/C++、Java 这类语言中都不是一等公民,一等公民的意思就是能够像其它整数、字符串变量一样,可以被赋值或者作为函数参数、返回值等。但是在 JS、Python 这类动态语言中,函数却是一等公民,可以作为参数、返回值等等。

究其原因,这类语言底层实现中,一切东西皆是对象。函数、整数、字符串、浮点数都是对象,函数才因此具备同其它基本类型一样的一等公民的身份。

在 C/C++ 中,函数虽然是二等公民, 但我们可以通过函数指针来变相的实现将函数用于变量赋值、函数参数、返回值场景。

1b1505eddf081101285005cdeda2a1b0.png

函数指针是啥?

我们知道普通变量申明后,编译器就会自动分配一块适合的内存。函数也是同样的,编译的时候会将一个函数编译好,然后放在一块内存中。

(上面这段说法实际很不准确,因为编译器不会分配内存,编译好的代码也是以二进制的形式放在磁盘上,只有程序开始运行时才会加载到内存)

如果我们把函数的首地址也存储在某个指针变量里,就可以通过这个指针变量来调用所指向的函数了,这个存储函数首地址的特殊指针就叫做函数指针

比如有一个函数 int func(int a);

我们如何申明一个可以指向 func 的函数指针呢?

int (*func_p)(int);

看起来有点奇怪,其实函数指针变量的声明格式和同函数 func 的声明一样,只不过把 func 换成(*func_p)罢了。

为什么要括号呢?因为不要括号的话 int *func_p(int); 就是申明一个返回指针的函数了,括号就是为了避免这种歧义

我们来多看几个函数指针的申明吧:

int (*f1)(int); // 传入int,返回int void (*f2)(char*); //传入char指针,没有返回值 double* (*f3)(int, int); //传递两个整数,返回 double指针

来看一个函数指针的具体用处吧:

# include

typedef void (*work) Work; // typedef 定义一种函数指针类型

void xiaobei_work {printf("小北工作就是写代码");}

void shuaibei_work {printf("帅北工作就是摸鱼")}

void do_work(Work worker) { worker;}int main(void){ Work x_work = xiaobei_work; Work s_work = shuaibei_work; do_work(x_work); do_work(s_work);return 0;}

输出:

小北工作就是写代码

帅北工作就是摸鱼

其实这里有点为了用函数指针而用了,不过大家应该体会到了,函数指针最大的优点就是将函数变量化了。

我们可以将函数作为参数传递给其它函数,于是就有了多态的雏形。我们可以传递不同的函数来实现不同的行为。

void qsort(void* base, size_t num, size_t width, int(*compare)(const void*,const void*))

这是 C 标准库中 qsort 函数的申明,它最后一个参数就要求传入一个函数指针,这个函数指针负责比较两个 element。

因为两个元素的比较方式只有调用者才知道,所以这里需要以函数指针的形式告诉 qsort 如何去判定两个元素的大小。

好了,函数指针就简单介绍到这里,接下来回到主题,对象。

782a66129fb755ca3fdecbf8d760e182.png

对象

那么在 C 语言中如何简单模拟一个对象呢?

当然只能靠结构体啦,而成员函数就可以通过函数指针来实现,其它的比如访问控制、继承等我们暂时不考虑。

struct Animal {char name[20];void (*eat)(struct Animal* this, char *food); // 成员方法 eatint (*work)(struct Animal* this); // 成员方法 工作};

但是 eat 和 work 都还没有任何具体实现,所以我们可以在一个初始化函数中构造 Animal 对象。

void eat(struct Animal* this, char *food) { printf("%s 在吃 %s

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值