近期事情特别多,睡眠也都非常晚,有点精神和身体混乱的感觉,所以想写写技术分析文章。让两者的我都调整一下。这篇技术分析文章是一直想写的,当前仅仅是开篇,有感觉的时候就写写,属于拼凑而成,兴许的篇章没有时间计划,随缘吧。

收藏家和杀手——面向对象的C++和C(一)

=========
用了至少12年的C++,前些年Linux之父Linus在批评C++的时候(详细可看CSDN的《C++一无是处》所提到的这起事件:http://www.csdn.net/article/a/2010-06-12/218785),引起了全世界非常多资深程序猿发起声讨C++的群体骚动。我尽管没有骚动,但还是跟在后面看了他们的大部分描写叙述。我得承认。他们说的大部分是事实(事实上每一个语言都有非常多能够批判的事实)。

作为一名有强迫症的程序猿(我坚信有强迫症的程序猿才是好程序猿),长期的C++经验让我在项目伊始就一直就纠缠在Code Style,Design Pattern、Framework等因素的形式是否优美、扩展性是否周到等问题,这些问题事实上就是内心重复自我怀疑式的噩梦,更糟糕的是这个噩梦的时间占用的项目周期还不少,尽管我个人也非常清楚,这些噩梦事实上和项目的最后目的没有直接关系(不会被老板、客户、用户看到)。并且也清楚噩梦的时间越长,就越和敏捷(Agile)的原型迭代流程以及精益(Lean Startup)思想背道而驰,但还似乎忍不住……这甚至类似于一种心理疾病。


相信非常多C++老程序猿都有和我同样的感觉,或许这个噩梦的起因能够解释为是由于我们都太想在编程中寻找一种完美和纯粹,但商业项目并不看重内里的完美和纯粹。换句话说就是我们想把艺术性的行为表如今代码中,让编程艺术化,但商业项目说“不是必需,能用就是好的”。

对于这个噩梦另一种更客观的解释,就是C++给了我们太多并且相互矛盾的选择(Java给我们的选择也非常多,但矛盾少了,组织的好一点)。而让我们这些强迫症患者无所适从,而商业项目仅仅要实现,才无论你怎么选择。

更通俗来说。就像打架,C++给我们了非常多武器。太多的选择和矛盾组合让我们无所适从,可以使用好这么多武器须要成年累月的经验,而商业项目就是最快最准的打倒对方,才无论你用啥。

想想看,当我拥有匕首、手枪、机关枪、火箭炮……时,我非常可能会忘了我的目的是打到对方,而当起了武器收藏家;但当我仅仅有匕首在手的时候呢?或许对方真正要倒霉了——我非常可能是个抱着誓死决心的杀手。


——所以有时候,少就是多,多就是少:)

从看到Linus对C++的批判開始。我就一直想能否够仅仅用C来写某个新项目,体验一下和C++敲代码的不同,可惜兴许好几个Linux的后台并发项目都还是用C++写的。直到近期一个项目,是涉及232和485接口的硬件传感器的Linux项目,才让我下决心所实用C来写。以下就来说说我的一些感想和总结。

杀手也可能成为收藏家——C也能够写基础的面向对象
=========
或许在看到C能够写面向对象这句话后。非常多初、中级程序猿惊呆了,觉得我胡说八道。假设我换个说法,C能够以面向对象的方式敲代码。但C语言本身并不直接具有面向对象的特性,这些程序猿或许就会好受一些,会从觉得我胡说八道转为觉得我有机会自圆其说。以下就让我自圆其说一下。

就语言本身而言,C语言的确不是一个面向对象的语言,但我们的问题是,那么C语言能够实现面向对象编程吗?我的答案是能够。面向对象就基本本质而言,没有那么复杂,事实上就是对数据和操作这些数据的方法的统一封装。

C++中有class(或者struct)这么一个keyword能够把数据和关联的方法封装成一个类。那么C语言呢?C语言的struct事实上也能够把数据和关联的方法封装在一起。

或许非常多人说。你骗人。C语言的struct中仅仅能放成员变量,不能放成员方法。或许你忘了还有函数指针这么一个东西,这个东西的存在,能够把方法像变量一样的放在C语言的struct中。例如以下(下面三个代码文件在Mac
OS X的XCode上完毕):


//

//  person.h

//  cthinking

//

//  Created by Rafael Gu on 14-8-25.

//  Copyright (c) 2014年 Rafael Gu. All rights reserved.

//

#ifndef _PERSON_H_

#define _PERSON_H_

struct person;

typedef unsigned char (*GET_AGE)(struct person *this);

typedef void (*SET_AGE)(struct person *this, unsigned char age);

// all public members

struct person {

];

GET_AGE get_age;

SET_AGE set_age;

};

struct person *person_create();

void person_destroy(struct person *p);

#endif // _PERSON_H_



//

//  person.c

//  cthinking

//

//  Created by Rafael Gu on 14-8-25.

//  Copyright (c) 2014年 Rafael Gu. All rights reserved.

//

#include "person.h"

#include <stdlib.h>

// all private members

struct _person {

unsigned char age;

};

static unsigned char _get_age(struct person *this)
{

struct _person *p = (struct _person *)(this
+ );

return p->age;

}

static void _set_age(struct person *this, unsigned char age)
{

struct _person *p = (struct _person *)(this
+ );

p->age = age;

}

struct person *person_create() {

struct person *p = (struct person *)malloc(sizeof(struct person)
+ sizeof(struct _person));

p->get_age = _get_age;

p->set_age = _set_age;

return p;

}

void person_destroy(struct person *p) {

free(p);

}

//

//  main.c

//  cthinking

//

//  Created by Rafael Gu on 14-8-25.

//  Copyright (c) 2014年 Rafael Gu. All rights reserved.

//

#include <stdio.h>

#include <string.h>

#include "person.h"

int main(int argc, const char *
argv[]) {

struct person *this = person_create();

, );

);

this->);

printf("%s's age is: %u\n", this->name, this->get_age(this));

person_destroy(this);

;

}



假设已经看懂上面代码的程序猿,应该会会心一笑,上面主要用了函数指针、struct的变体偏移、编译单元的static函数(变量也相同)等C的技术。假设是写过objective-c的程序猿,立即就会认为和不同private和publickeyword的objective-c的类结构非常像。


在上面的类中,name是public变量。age是私有变量。通过相应的getter和setter訪问。person_create能够看做是new和构造函数的结合体,而person_destroy能够看做是delete和析构函数的结合体。

当然这里仅仅实现了private和public,没有protected。


假设有人问。怎样实现class的static函数和变量。事实上他们就是C的编译单元的static函数和变量。仅仅要看懂上面的代码,而且知道编译单元是啥以及和static什么关系就明确了。


今天就写到这里。下次假设再写,就像写高级一点的面向对象知识了,比方多态。当然为了防止没有下文的遗憾,我这里把实现多态的技术原理说一下:
  • 继承——你看上面的person和_person的struct变体偏移就知道怎样组合不同结构体实现继承了。
  • 重载、虚函数——你看上面的函数指针在“构造”函数才被指定。那么你应该明确怎样实现重载和虚函数了。

最后。这里要说一下,我仅仅是在用C写面向对象,并非要把C++或者Java的每一个语言级的面向对象特性都展示出来。当然要展示。C也全然能够做得到。

我的项目是基于上面代码的对象方式写得。假设全然实现C++或者Java的全部面向对象特性。也不太有用。

2014年8月25日,收藏家和杀手——面向对象的C++和C(一)的更多相关文章

  1. 09.25日记(2014年9月25日23:22:06)用java这么多年面向对象我真的懂了吗,测试先行理念会玩吗

    二胡 (1)应该找些书来看看,工作N年并不代表就有N年的工作经验. (2)DiaTransit02,DiaDept02,DiaAirport02,DiaHighway02.都具有x,y属性为何不设计一 ...

  2. SE 2014年5月25日

    如图配置 两实验 R1模拟总部,R2 与R3模拟分部 实验一  要求使用 IPSec VPN 主模式,使得总部与两分部内网可相互通讯 步骤: 1.  配置默认路由 [RT1]ip route-stat ...

  3. SE 2014年4月25日

    1. 描述 STP 的计算过程 (1.根桥的选举 2.端口角色的确定) 根桥的选举 启用STP后,网络中桥ID最小的交换机会被选为根桥,桥ID由桥优先级和桥MAC两部分组成,优先级默认为32768,首 ...

  4. 马后炮之12306抢票工具(四)--抢票Demo,2014年1月9日终结版

    时隔一年多,终于朋友的忽悠下吧抢票Demo的最后一步完善了,与2014年1月9日成功生成车票. Demo仅经过自己测试,并未在高峰期进行测试,代码质量很差,因为赶工,套用去年模板并未使用设计模式. 代 ...

  5. 无插件的大模型浏览器Autodesk Viewer开发培训-武汉-2014年8月28日 9:00 – 12:00

    武汉附近的同学们有福了,这是全球第一次关于Autodesk viewer的教室培训. :) 你可能已经在各种场合听过或看过Autodesk最新推出的大模型浏览器,这是无需插件的浏览器模型,支持几十种数 ...

  6. 系列文章:老项目的#iPhone6与iPhone6Plus适配#(持续更新中,更新日期2014年10月12日 星期日 )

    本文永久地址为http://www.cnblogs.com/ChenYilong/p/4020399.html ,转载请注明出处. ********************************** ...

  7. 2016年12月25日 星期日 --出埃及记 Exodus 21:20

    2016年12月25日 星期日 --出埃及记 Exodus 21:20 "If a man beats his male or female slave with a rod and the ...

  8. 转:[置顶] 从头到尾彻底理解KMP(2014年8月22日版)

    [置顶] 从头到尾彻底理解KMP(2014年8月22日版)

  9. SQLSERVER2014 2014年4月1日发布

    SQLSERVER2014 2014年4月1日发布 原文地址: http://blogs.technet.com/b/microsoft_blog/archive/2014/03/18/sql-ser ...

随机推荐

  1. layer弹窗在键盘按回车将反复刷新

      条件:弹窗后不做任何点击操作或者聚焦操作对于layer.load,弹出后反复按回车,load层将不断刷新,即使设置了自动消失也只有等不按回车键才会生效.对于layer iframe层有表单就更糟糕 ...

  2. ruby操作mysql

    require "win32ole" require 'pathname' require 'mysql2' excel = WIN32OLE.new('excel.applica ...

  3. 设计模式(四)建造者模式 Builder

    Builder: <Effective Java> 第2条:遇到多个构造器参数时要考虑用构建器. 建造者模式(Builder Pattern),也称生成器模式,定义如下: 将一个复杂对象的 ...

  4. iOS--------对堆、栈 存储空间的理解

    Objective-C的对象在内存中是以堆的方式分配空间的,并且堆内存是由你释放的,即release 栈由编译器管理自动释放的,在方法中(函数体)定义的变量通常是在栈内,因此如果你的变量要跨函数的话就 ...

  5. hdu5730 Shell Necklace 【分治fft】

    题目 简述: 有一段长度为n的贝壳,将其划分为若干段,给出划分为每种长度的方案数,问有多少种划分方案 题解 设\(f[i]\)表示长度为\(i\)时的方案数 不难得dp方程: \[f[i] = \su ...

  6. ubuntu通过cifs-utils访问Windows共享目录

    ubuntu旧一点的版本如:12.0x是用smbclient访问window共享的,但比较新的版本如:16.04是通过cifs-utils访问Windows共享目录 同样道理先安装: apt-get ...

  7. Spring Boot 配置大全

    Spring Boot 允许通过外部配置让你在不同的环境使用同一应用程序的代码,简单说就是可以通过配置文件来注入属性或者修改默认的配置. SpringBoot的配置方式有很多,它们的优先级如下所示(优 ...

  8. Number Sequence(poj 1019)

    题意: 有一串数字串,其规律为 1 12 123 1234 12345 123456 1234567 12345678 123456789 12345678910 1234567891011 1234 ...

  9. 【bzoj4031】[HEOI2015]小Z的房间 && 【bzoj4894】天赋 (矩阵树定理)

    来两道矩阵树模板: T1:[bzoj4031][HEOI2015]小Z的房间 Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形 ...

  10. 将xml转换为PHP数组

    这里提供一个类来将XML转换为PHP数组,下面是类的代码 <?php/** * XML2Array: A class to convert XML to array in PHP * It re ...