五千年(敝帚自珍)

主题:【注意】道歉--刀耕火种的繁荣时代 的连接上次给错了 -- 柚子

分页树展主题 · 全看首页 上页
/ 1
下页 末页
  • 家园 【注意】道歉--刀耕火种的繁荣时代 的连接上次给错了

    外链出处

    刀耕火种的繁荣时代

    刘新宇

    2006年三月

    在以前的一篇文章《资源管理的变法》中,我曾经为了读者理解方便,刻意把宋朝说成自然环境恶劣,生产落后的“刀耕火种”时代。这其实是胡言乱语的,不可当真。实际上宋朝可以说是我国古代极其繁荣的一个顶点。经过了宋朝连年战乱后的元朝,其繁荣和文明的程度仍然让马可波罗感到震惊。在他的游记中即使除去关于元大都的叙述,对于南宋故都杭州的描写,也仍然让人惊讶不已。

    问题就是在于,在我们现代人看来的“刀耕火种”时代,没有电,没有石油,没有汽车,没有空调和抽水马桶,文明和繁盛是如何实现的呢?

    如果说今天软件开发界的文明和繁盛中,面向对象是一个代表;C++和Java这些是实现繁荣的电,石油和汽车。那么在“刀耕火种”的时代,只有ANSI C这个冷兵器,如何实现“盛世”呢?

    首先要看一看盛世的特点,比如汉代的“文景之治”,唐代的“贞观之治”“开元盛世”。在物质丰富的同时,政治也比较宽松,文化得到发展。这些都可以归纳成一些特点。在软件开发领域,面向对象也有一些特点,最主要的是如下三个:

    封装性

    继承性

    多态性

    按照一贯的风格,为了方便读者理解,这里按部就班,把上述三个特性类比为文明社会的3个特点:

    封装性——政治组织制度

    继承性——人才选拔制度

    多态性——财政税收制度

    实现手法上,做这样的类比:

    C++的实现手法——现代社会的实现手法

    C 的实现手法——古代社会的实现手法

    最后本文再给出在不支持多线程的操作系统上实现多线程的手法。

    首先看文明社会中的政治组织制度。政治组织中非常重要的一点就是“按部就班,各司其职”。同时官员和职能也明确划分,共同“封装”在指定的部门里。对应于面相对象的封装性,其特征也是如此。这一特性把算法和数据结构等在概念上属于同一事物的内容,统一包装起来,例如C++中:

    class Encapsulate{

    public:

    void setValue(const int v){value=v;}

    const int getValue() const {return value;}

    private:

    int value;

    };

     

    包装内部既有数据value,也有方法如setValue和getValue,这些方法可以按照非常明确的从属关系加以调用,例如:

     

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

    Encapsulate v;

    v.setValue(3);

    cout<<"value = "<<v.getValue()<<"\n";

    //error cout<<v.value;

    reuturn 0;

    }

    政府分门别类,官员按部就班。现代文明社会可以,汉代的“九品中正”,唐代的“三省六部”也行。用ANSI C实现封装性的思路是使用函数指针。由于在ANSI C中,结构体的含义类似C++和Java中的类。虽然C中的结构体不允许含有函数成员,但是函数指针可以被当作普通的数据成员放入结构体中。唯一要做的就是,一定要正确初始化这些函数指针。所以ANSI C实现的封装特性如下:

    首先在头文件中:

    struct Encapsulate{

    int value;

    void (*setValue)(struct Encapsulate* p, const int v);

    const int (*getValue)(struct Encapsulate* p);

    };

    struct Encapsulate* create();

     

    然后在C文件中:

    static void setValue(struct Encapsulate* p, const int v){

    p->value=v;

    }

     

    static const int getValue(struct Encapsulate* p){

    return p->value;

    }

     

    struct Encapsulate* create(){

    Encapsulate* p=(Encapsulate*)malloc(sizeof(Encapsulate));

    p->setValue=setValue;

    p->getValue=getValue;

    return p;

    }

     

    现在可以看看封装的效果:

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

    Encapsulate* e=create();

    e->setValue(e, 3);

    printf("value = %d\n", e->getValue(e));

    free(e);

    reuturn 0;

    }

     

    不仅输出和前面一摸一样,而且在调用方式上也非常相似。如果为了理解方便,还可以定义一个self变量:

    struct Encapsulate{

    //略

    struct Encapsulate* self;

    };

    在初始化create时:

    struct Encapsulate* create(){

    Encapsulate* p=(Encapsulate*)malloc(sizeof(Encapsulate));

    p->self = p;

    p->setValue=setValue;

    p->getValue=getValue;

    return p;

    }

    这样调用的时候,就可以按照这个形式:

    e->setValue(e->self, 3);

    人才选拔和培养是现代文明社会中非常重要的一环,通过人才的培养和选拔,社会中沉淀的知识和经验得以积累,前人的成果得以被后人“继承”。继承性是“文明中”代码重用的重要基础之一。在C++中,子类从父类继承,可以获得父类的大量特性,例如:

    class Base{

    public:

    void setValue(int v){value=v;}

    int getValue(){return value;}

    int value;

    };

     

    class Derived:public Base{

    public:

    void increase(){value++;}

    void decrease(){value--;}

    int key;

    };

     

    子类通过继承,可以在具有父类所有特性的同时,再增加子类特殊的内容,而原来针对父类的操作,也可以针对子类而不必重新改动,例如:

     

    void initBase(Base* p){

    p->setValue(0);

    }

     

    void display(Base* p){

    cout<<"value="<<p->getValue()<<"\n";

    }

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

    Derived foo;

    initBase(&foo);

    foo.increase();

    foo.increase();

    display(&foo);

    foo.decrease();

    display(&foo);

    foo.key=3;

    }

     

    现代社会通过社会化的教育体系实现的功能,在古代社会同样可以实现,春秋时孔子就搞“民间教育”,弟子三千,贤者七十有二。在选拔上,现代社会有各种考试,在汉代有“举孝廉和举秀才”,唐代开始有国家统一的考试。因此继承性不是C++和Java的专利,也可以通过ANSI C加以实现,思路是在子结构体的起始位置,放入父结构体的一段数据[3]。这样只要将子结构体强制类型转换为父结构体后,就可以直接被直接当作父结构体操作。这样操作不会出现问题的原因在于,那些针对父结构体的函数,只会访问子结构体数据的前面一段,而不会访问到后继的数据部分。这个思路用ANSI C实现如下:

     

    首先在头文件中这样定义:

    struct Base{

    void (*setValue)(struct Base* self, int v);

    int (*getValue)(struct Base* self);

    int value;

    };

    void constructBase(struct Base* p);

     

    struct Derived{

    struct Base base; /*实现继承*/

    void (*increase)(struct Derived* self);

    void (*decrease)(struct Derived* self);

    int key;

    };

    void constructDerived(struct Derived* p);

     

    void initBase(struct Base* p);

    void display(struct Base* p);

    由于C中没有构造函数的概念,所以constructXXX负责了一部分的任务,在C文件中,上述定义的实现如下:

    /* Base member functions */

    static void setValue(struct Base* self, int v){

    self->value=v;

    }

     

    static int getValue(struct Base* self){

    return self->value;

    }

     

    void constructBase(struct Base* p){

    p->setValue=setValue;

    p->getValue=getValue;

    }

     

    /* Derived member functions */

    static void increase(struct Derived* self){

    self->base.value++; /*或者((struct Base*)self)->value++;*/

    }

     

    static void decrease(struct Derived* self){

    self->base.value--; /*或者((struct Base*)self)->value--;*/

    }

     

    void constructDerived(struct Derived* p){

    constructBase((struct Base*)p); /*调用父类构造函数*/

    p->increase=increase;

    p->decrease=decrease;

    }

     

    /* global functions */

    void initBase(struct Base* p){

    p->setValue(p, 0);

    }

     

    void display(struct Base* p){

    printf("value=%d\n", p->getValue(p));

    }

     

    上面代码中,最体现特点的是带有汉字的注释部分,这些都表明,子结构一旦向上转换为父结构后,就可以被当作父结构来对待。这是面向对象中继承的英文解释:is a type of的良好诠释。下面可以测试一下:

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

    struct Derived foo;

    constructDerived(&foo);

     

    initBase((struct Base*)&foo);

     

    foo.increase(&foo);

    foo.increase(&foo);

    display((struct Base*)&foo);

     

    foo.decrease(&foo);

    display((struct Base*)&foo);

     

    foo.key=3;

    return 0;

    }

     

    调用方式和前面C++的基本一致,输出结果也一摸一样。

     

    文明社会的政府为了保证其财政收入,都拥有一套财政税收制度。基本含义不变而课税方法多样,有的关注生产环节,有的关注流通环节,还有的着眼在消费。这样的“多态性”可以保证提纲挈领,纲举目张。在C++中多态性(这里是指运行时的多态,实现编译期多态的模板技术暂不讨论)通过虚函数(virtual function)和override/overwrite进行实现(这里暂且不提overload)。例如:

     

    class Point{

    public:

    Point(int _x, int _y):x(_x), y(_y){};

    virtual double radius(){ return sqrt(double(x*x+y*y)); }

    int x;

    int y;

    };

     

    class Point3D:public Point{

    public:

    Point3D(int _x, int _y, int _z):Point(_x, _y), z(_z){};

    double radius(){return sqrt(double(x*x+y*y+z*z)); }

    int z;

    };

     

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

    Point* p=new Point(1,1);

    cout<<"radius ="<<p->radius()<<"\n";

    delete p;

     

    p= new Point3D(1,1,2);

    cout<<"radius ="<<p->radius()<<"\n";

    delete p;

    }

     

    在这个例子里,Point定义了平面上的点,而Point3D定义了空间上的点,当计算点到原点的距离radius的时候,平面的计算方法和空间的计算方法不同,在这里多态的表现就是,子类Point3D重新实现了父类Point的计算方法,而其他内容则采取“拿来主义”一并继承过来。

     

    虽然现代社会拥有完善的各种课税,比如生产和销售环节的增值税,建筑服务行业的营业税,针对企业和个人的所得税,其根本是提供国家的财政收入。在中国古代,春秋时期鲁国在前594年即实行了“初税亩”,按照土地向私有者课征。此后各朝变迁变法,税收都是其中重要一环。用ANSI C实现多态的方法如下:

     

    首先在头文件中定义普通平面上的点和三维空间的点,并按照前面的做法,建立继承关系,为了说明多态的灵活性,还增加了一个彩色平面点的定义。:

    struct point{

    double (*radius)( struct point* self);

    void (*display)(struct point* self, const char* name);

    int x;

    int y;

    };

    struct point* create_point(int x, int y);

     

    struct point3D{

    struct point super;

    int z;

    };

    struct point* create_point3D(int x, int y, int z);

     

    enum color_t{RED, GREEN, BLUE};

    struct color_point{

    struct point super;

    enum color_t color;

    };

    struct point* create_color_point(int x, int y, enum color_t color);

     

    在这套继承体系中,三维空间点和彩色平面点都从普通平面点继承来,但是在使用虚函数实现多态上有一些区别。三种点各自实现显示信息的方法display,但是彩色点直接使用平面点的radius方法计算到原点的距离,而三维空间点则override这个计算的方法。具体的实现如下:

     

    /* point in 2D plan default member function */

    static double radius(struct point* self){

    return sqrt((double)(self->x*self->x + self->y*self->y));

    }

     

    static void display(struct point* self, const char* name){

    printf("point %s: x=%d, y=%d\n", name, self->x, self->y);

    }

     

    static void init_point(struct point* p, int x, int y){

    p->x=x;

    p->y=y;

    p->radius=radius;

    p->display=display;

    }

     

    /* point ctor */

    struct point* create_point(int x, int y){

    struct point* p=(struct point*)malloc(sizeof(struct point));

    init_point(p, x, y);

    return p;

    }

     

    普通平面点得以实现后,现在实现三维点,需要override的方法包括radius和display,另外在构造时还要额外初始化z成员:

    /* point3D overrided member function */

    static double radius3D(struct point* self){

    /* downcasting will cause warning */

    struct point3D* p=(struct poin3D*)self;

    return sqrt((double)(self->x*self->x+

    self->y*self->y+

    p->z*p->z));

    }

     

    static void display3D(struct point* self, const char* name){

    struct point3D* p=(struct poin3D*)self;

    printf("3D point %s: x=%d, y=%d, z=%d\n", name, self->x, self->y, p->z);

    }

     

    static void init_point3D(struct point3D* p, int z){

    p->z=z;

    ((struct point*)p)->radius=radius3D; /* override */

    p->super.display=display3D; /* override */

    }

     

    /* point 3D ctor */

    struct point* create_point3D(int x, int y, int z){

    struct piont3D* p=(struct point3D*)malloc(sizeof(struct point3D));

    init_point((struct point*)p, x, y);

    init_point3D(p, z);

    return (struct point*)p;

    }

     

    平面上的彩色点直接使用父类的radius函数,但是需要override计算距离的radius函数。

    /* color point used its fathers radius methods,

    * only display function is overwrote

    */

    static void display_color(struct point* self, const char* name){

    struct color_point* p=(struct color_point*)self;

    printf("color point %s: x=%d, y=%d, color=%d\n", name, self->x, self->y, p->color);

    }

     

    static void init_color_point(struct color_point* p, enum color_t color){

    p->color=color;

    p->super.display=display_color; /* only display function is overridden */

    }

     

    /* color point ctor */

    struct point* create_color_point(int x, int y, enum color_t color){

    struct color_piont* p=(struct color_point*)malloc(sizeof(struct color_point));

    init_point((struct point*)p, x, y);

    init_color_point(p, color);

    return (struct point*)p;

    }

    现在可以测试一下这套继承体系的多态特性:

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

    struct point* p=create_point(1, 1);

    printf("radius of p1=%f\n", p->radius(p));

    p->display(p, "p1");

    free(p);

     

    p=create_point3D(1, 1, 2);

    printf("radius of p2=%f\n", p->radius(p));

    p->display(p, "p2");

    free(p);

     

    p=create_color_point(1, 1, RED);

    printf("radius of p3=%f\n", p->radius(p));

    p->display(p, "p3");

    free(p);

     

    return 0;

    }

    调用方法和C++的如出一辙,运行结果如下:

    radius of p1=1.414214

    point p1: x=1, y=1

    radius of p2=2.449490

    3D point p2: x=1, y=1, z=2

    radius of p3=1.414214

    color point p3: x=1, y=1, color=0

    输出结果也和预想的一致,至此“刀耕火种”的ANSI C基本实现了用C++和Java体现出的面向对象三大特性。当然这里还有不完美的地方,比如没有办法限制访问权限。C++和Java提供语言级别的public, private等关键字来实现一定程度的数据隐藏。在本文的实现方法中,虽然可以通过把方法置于C文件内部实现部分private意义上的隐藏,但是却暴露了所有的数据成员。另外C++和Java都提供的函数overload,也没有给出有效的实现。但这已经不足以阻止用“刀耕火种”建立“繁荣时代”了。古代文明的魅力也正在于此。

    盛世还有一些代表性的城市繁荣,比如唐的长安,北宋的汴梁,南宋的杭州。虽然现代化的大都市有惊人的硬件环境,但是在缺乏这些现代化硬件的古代,依然能够实现城市的繁荣。比如现代操作系统,天生支持多线程。可是在不支持多线程的系统上,依然不能阻止实现运算调度的尝试。这些尝试虽然不是本质上的并行处理(现代操作系统在单CPU下也不是真正意义上的并行,而是时间片的调度,当然Intel最近热炒的双核不算在内),但是依然能够给使用者并发的感觉。

    下面就用C++语言本身(不使用任何多线程库)实现多线程的感觉。其思路来自一种称之为ActiveObject[4]的模式。这种思路往往类似传统的戏剧。比如《三国演义》里面长板坡,开始情节单一,过一会就出现了两个条线(thread),一条线赵云冲进去救刘备家小去了。另一条线张飞护着刘备跑,并且设置假伏兵。两条线同时发生,都要演出,可是却只有一个舞台。办法是舞台上先演一段赵云,张飞等演员在后台休息,然后大幕落下,赵云等演员撤到后台休息,张飞他们出来再演一段。然后再次赵云上前台演,张飞去后台休息……如此往复。观众们丝毫不觉得奇怪,而很自然的认为这两段故事同时发生。演出的关键在于合理的分隔每段故事上演的时间片,让观众没有割裂的感觉。这个思路其实就是单CPU,单进程实现多线程的思路。

    首先定义一个线程类,这个就是张飞和赵云的故事这种并发故事的抽象描述:

    class thread{

    public:

    thread(int period):period_(period*1000),time_(0){};

     

    virtual void run()=0;

    virtual bool finish()=0;

     

    bool wait(){

    return (time_++%period_)!=0;

    }

    private:

    long period_;

    long time_;

    };

    线程的构造函数中,导演可以事先决定每段故事的演员要在后台休息的时间period,每次休息时间一到(time_++%period为0的时候),演员们就停止休息上前台演出(run)。故事的每条线有一个结束的标志finish,当故事结束时,就再也不用到舞台上演出了。

    舞台调度的实现如下:

    class schedular{

    public:

    static schedular& instance(){

    static schedular inst;

    return inst;

    }

     

    void start(){

    while(!queue_.empty()){

    thread* p=queue_.front();

    queue_.pop_front();

     

    if(!p->wait())

    p->run();

     

    if(!p->finish())

    queue_.push_back(p);

    else

    delete p;

    }

    }

     

    void add(thread* p){

    queue_.push_back(p);

    }

     

    ~schedular(){

    while(!queue_.empty()){

    delete queue_.front();

    queue_.pop_front();

    }

    }

    private:

    schedular(){}

    schedular(const schedular&);

    const schedular& operator=(const schedular&);

     

    list<thread*> queue_;

    };

     

    舞台只有一个,所以被设计为singleton。在演出前,导演可以预先把这些故事线索(thread)加入到舞台调度的列表(queue_)中去,然后一旦演出开始(start),舞台调度就不断查看调度表,把表头的故事拿出来,看看是否他们应该上台,如果该上台了,就通知他们演出(run)一段。这段演出结束后,调度询问他们所演的全部故事是否已经结束了,如果还没有,就把他们的故事再次放到调度表的最后面,然后去准备演下一条故事线索。一旦这个故事线索演出完毕,比如说赵云已经抱着阿斗冲出来了,调度就不会再把故事放到调度表的最后。赵云就可以卸装喝水彻底休息了。

     

    现在就可以给出一个具体的故事线索作为例子了:

    class counter: public thread{

    public:

    counter(const string name, int value, int s):thread(s), name_(name), value_(value){}

     

    void run(){

    cout<<"thread "<<name_<<": count "<<value_--<<"\n";

    }

     

    bool finish(){

    return (value_<=0);

    }

    private:

    string name_;

    int value_;

    };

    这个故事就是:“从前有座山,山上有个庙,庙里有个和尚在将故事,讲的故事是:从前有座山……”这样的循环故事,每次上台演出就讲一句,直到讲到累了(value_为0)为止。每次在后台休息s-1分后,上台讲一句。

    此后就可以演出了,导演让两个这样的故事线索同时上演,间隔的时间不同:

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

    schedular::instance().add(new counter(string("hello"), 20, 2));

    schedular::instance().add(new counter(string("me"), 10, 5));

    schedular::instance().start();

    }

    演出的效果如下:

    thread hello: count 20

    thread me: count 10

    thread hello: count 19

    thread hello: count 18

    thread me: count 9

    thread hello: count 17

    thread hello: count 16

    thread hello: count 15

    thread me: count 8

    thread hello: count 14

    thread hello: count 13

    thread me: count 7

    thread hello: count 12

    thread hello: count 11

    thread hello: count 10

    thread me: count 6

    thread hello: count 9

    thread hello: count 8

    thread me: count 5

    thread hello: count 7

    thread hello: count 6

    thread hello: count 5

    thread me: count 4

    thread hello: count 4

    thread hello: count 3

    thread me: count 3

    thread hello: count 2

    thread hello: count 1

    thread me: count 2

    thread me: count 1

    作为现在的中国人,多少对“古代盛世”怀有一些复杂的情节。有的人怀念,恨不得能够回到唐朝去生活;有的人理性地说光是晚上没有电就受不了。有时面对计算机,手机,汽车这些东西,我也会怀疑究竟人类技术的发展是一种社会的进步还是倒退。有时候看到早上一路小跑赶公共汽车的人们生怕上班打卡迟到,我也会想究竟古代是否要活的这么紧张。

    现代人还是很难摆脱历史的阴影,we learn from history that people never learn from history,看着我们一遍一遍重复古人走过的轨迹——揭竿而起,励精图治,贪污腐败,天灾人祸,战乱流离……这样兴衰治乱的演出,上帝一定也觉得很没有意思吧。

    参考书目:

    [1] Apache httpd source code: http://httpd.apache.org/

    [2] APR, apache runtime library source code: http://apr.apache.org/

    [3] Peter. Wright. Beginning GTK/GNOME programming. Peer Information. 2000

    [4] Robot C. Martin, Agile software development: principles, patterns, and practice. Printice Hall. 2002.

    • 家园 【讨论】几个商榷的地方

      1)

      void setValue(const int v){value=v;}

      C/C++是Pass-by-value,所以对于简单数据类型的传值,const是不必要的。

      一般在传一个reference或pointer的Input parameter使用const,来避免其内容被函数修改。

      2)Point和Point3D之间不存在继承关系。(而Point和color_point之间存在继承关系)。

      C++的继承关系是严格的IS_A关系,也就是说,Derived class必须拥有base class的所有public和protected属性和method。Base class的public virtual function可视作derived class的一个default implementation。(在base class无法缺省实现时,则常为pure virtual function),显然因为3D的Point多了一个z坐标,彻底改变了2维点的物理意义,两者没有这种IS_A关系。严格来说这更像一个Has-A关系。

      虽然数学上两者有紧密联系,而在C++中因为不是严格的IS_A关系,所以不能使用继承。

      因为多一个Z-坐标,2D point和3D point只能视作两个独立的class,或许实现上3D point class可以composite 2D point class.

      Scott Meyers在他的Effective C++有一个Item(记不清是具体哪个Item了)是专门解释这一点了。记得他老人家举的例子是,矩形和正方形之间不存在继承关系。

      3)Thread这个例子有个明显问题,

      queue_不是thread safe的,对queue_的操作应要加上Mutex或其他类似的东东加以保护。

      • 家园 谢谢回贴

        首先谢谢回贴,有讨论才能有进步,沙龙永远胜过一言堂。

        >void setValue(const int v){value=v;}

        >

        >C/C++是Pass-by-value,所以对于简单数据类型的传值,const是不必要的。

        >一般在传一个reference或pointer的Input parameter使用const,来避免其内容被函数修改。

        这点非常同意,实际上应该是这样的:

        TypeResult function(const TypeClass& v){ //pass const reference to avoid temp copy ctor

        value=TypeClass(v); //保护性copy,防止v是一个cracker恶意继承自TypeClass的类

        }

        对于上述setValue,本质希望能够直接对比到ANSI C的实现上,如果涉及保护性copy,和pass by reference

        及pass by value,这些language-level的特性,并不是OO的特性,也无法和ANSI C的实现对比了。

        >2)Point和Point3D之间不存在继承关系。(而Point和color_point之间存在继承关系)。

        >C++的继承关系是严格的IS_A关系,也就是说,Derived class必须拥有base class的所有public和protected属性和 >method。Base class的public virtual function可视作derived class的一个default implementation。(在base >class无法缺省实现时,则常为pure virtual function),显然因为3D的Point多了一个z坐标,彻底改变了2维点的> 物理意义,两者没有这种IS_A关系。严格来说这更像一个Has-A关系。

        >虽然数学上两者有紧密联系,而在C++中因为不是严格的IS_A关系,所以不能使用继承。[cchere.com 西西河 无> 斋主人]

        >因为多一个Z-坐标,2D point和3D point只能视作两个独立的class,或许实现上3D point class可以composite 2D >point class.

        >Scott Meyers在他的Effective C++有一个Item(记不清是具体哪个Item了)是专门解释这一点了。记得他老人家举> 的例子是,矩形和正方形之间不存在继承关系。

        关于inheritance和compose,这个也是最近OO中特别强调的一点。例子很多,事实上在某些极端的情况下比如Java, 只有interface可以被implement,而不主张继承任何非抽象类。总之,的确继承在前些年被滥用了,更多的情况下

        应该是compose,但是如果你仔细读我的ANSI C代码,就会发现,使用ANSI C实现继承时,只有一个办法——就是 compose,sub struct HAS_A base struct data section。

        严格说,按照OO思想,如果采用C++或者JAVA这个继承体系如下:

        template<class T>

        class point{

        public:

        virtual const T& getCoordinate(int demension) = 0;

        virtual double radius() = 0;

        };

        tempalte<int n, class T = int>

        class pointX: public point<T>{

        public:

        const T& getCoordinate(int demension){

        if(demension < 0 || demension > n)

        throw std::runtime_error("out of demension");

        return coordinates[n];

        }

        double radius(){

        for(int i=0, res=0; i<n; ++i)

        res+=coordinates[i]*coordinates[i]

        return sqrt(res);

        }

        private:

        T[n] coordinates;

        };

        typedef piontX<2> point2D;

        typedef pointX<3> point3D;

        class colored_point:public point2D{

        //...

        };

        >3)Thread这个例子有个明显问题,

        >queue_不是thread safe的,对queue_的操作应要加上Mutex或其他类似的东东加以保护。

        这个我觉得你没有理解我的意思,我是在不支持多线程的机器上实现多线程,例如在MS-DOS上,

        只有我一个process一个task,哪里有同步的问题呢?

分页树展主题 · 全看首页 上页
/ 1
下页 末页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河