Rainyboy 发表于 2010-11-6 21:55

关于OOP中若干特性的思考

本帖最后由 Rainyboy 于 2010-11-6 22:00 编辑

       由于最近在学习Python,了解了很多所谓Python的新特性,无非是更加方便和精确地实现了面对对象(OOP)编程的精髓。有些网友甚至急匆匆地就拿Python与各种语言作比较了,我想说的是,并非C++不能这样做,是因为它不必这样做(关于C++的四种编程层面,请参考《Effective C++》,面对对象编程,只是其中的一种)。

       要想用C++实现这些现代面对对象编程语言的典范功能,并不需要改进语法,只需要精妙地构建一些类和宏就可以了,关于这项工作的典范,是微软出品的MFC(Microsoft Fundation Class)系列库类,设计这些库类的出发点,是将面对对象的观点引入基于windows的应用程序设计上,其亮点在于这是一个完全构建在C++之上的库类,并没有修改C++语法,实现了WINDOWS下面对对象编程所谓的“六大关键技术”,分别是:
      类层级结构(对应于Python的“万物皆对象”思想,所有的MFC类都有共同的基类:CObject类);
      运行时类型识别(对应于Python的type()函数,接受任何东西作为参数,返回的字符串告诉你这个东西是什么类别);
      动态创建(相当于Python的cPickle库或者Pickle库的load()函数,从文件中还原类的实例);
      永久保存(相当于Python的cPickle库或者Pickle库的dump()函数,将类的实例保存到文件);
      消息映射(操作系统相关的技术);
      命令传递(操作系统相关的技术);

       当年在研习候俊杰的《深入浅出MFC》时,照着书上的讲解构建了一个可以实现“动态创建”和“运行时类型识别”以及“永久保存”的“类层级结构”。再贴代码之前,让我再说说这四个名词的意思吧,实际上,我认为,他们只是一个问题的四个方面:
       因为我们要实现最纯粹的面对对象编程,即按照“万物皆对象”的观点,能操作的所有东西都应该是某个类的对象,而类与类之间的关系,应该组织在一张大“网”中,什么类的子类是什么,万物的源头是什么类,等等。库类框架中各类的关系,构成了类层级结构。
       既然万物皆对象,我们有理由要求像保存数据一样将我们操作的对象保存在磁盘上,这就是永久保存技术,而且在需要的时候从磁盘读入内存并再现这个对象,这就是动态创建技术;这两个技术要求我们必须做到,在一个类被创建出来后,还能获知他是什么类的对象,这就是运行时类型识别技术;
       让我们来想想运行时类型识别:
       例如,在Human类->Man类->Child类这样的框架中,要执行一个全局的FindAWomanToMarry(Human *p),就要先确定当前的p是什么?当然,我们知道它是Human类,子类和父类总是有Is-A关系,即Chinld类的对象是一个 Human类对象( Child IS A Human)。但是我们无法知道p表示的是Human的那个子类的对象,当然我们有其它办法例如获取年龄值等等来避开这个特定的问题,但是并没有回答我们为了说明的那个问题:怎么在一个类的对象被创建出来之后还能得到这个对象在类层级结构中的位置?)

    说了这么多,总而言之,我认为,运行时类型识别、动态创建、永久保存和类层级结构是面对对象语言(或框架)所必须提供的特性。MFC框架和《深入浅出MFC》告诉我们,如何在C++中构造出这出这些特性。
   
    多年前的依样画葫芦的一些代码,帖出来给大家看看吧。
    RTCT.h :包含非常精妙的宏定义,是实现运行时类型识别的关键


#ifndef RTTCTRT
#define RTTCTRT
#define FIRST_CLASS Human
#define RTTI_PRE(X)\
   static RUNTIMECLASS X##class;\
   virtual RUNTIMECLASS* GetRunTimeClass() const;
#define RTTI_LINK(new_class,basic_class)\
static char new_class##_p[]=#new_class;\
RUNTIMECLASS new_class::new_class##class={\
      new_class##_p,sizeof(new_class),&basic_class::basic_class##class,NULL,NULL};\
static RFX_init init##new_class(&new_class::new_class##class);\
RUNTIMECLASS* new_class::GetRunTimeClass() const\
{return &new_class::new_class##class;}\
#define RTCT_PRE(X) \
    static RUNTIMECLASS X##class;\
    virtual RUNTIMECLASS* GetRunTimeClass() const;\
    static Human* RUNTIMECREAT();
#define RTCT_LINK(new_class,basic_class)\
Human *new_class::RUNTIMECREAT()\
{return new new_class; }\
static char new_class##_p[]=#new_class;\
RUNTIMECLASS new_class::new_class##class={\
new_class##_p,sizeof(new_class),&basic_class::basic_class##class,new_class::RUNTIMECREAT,NULL};\
static RFX_init init##new_class(&new_class::new_class##class);\
RUNTIMECLASS* new_class::GetRunTimeClass() const\
{return &new_class::new_class##class;}
/////////////////////////////////////////////////
    class FIRST_CLASS;
/*在引用之前,这是非常必要的*/
struct RUNTIMECLASS
{
char * name;
int size;
RUNTIMECLASS *basic;//指向父类
    FIRST_CLASS* (*pf_Creat)();
    FIRST_CLASS* RTCreat();
RUNTIMECLASS *next;//指向下一节点
staticRUNTIMECLASS *First;
};
/////////////////////////////////////////////////
class RFX_init
{
public:
RFX_init(RUNTIMECLASS *newclass);
};
#endif
    UDF.h:自己构建的几个类,形成一个以Human类为源头的小框架
#ifndef UDFF
#define UDFF
#define R_DEBUG
#include "RTCT.h"
int CMP(char s1[],char s2[]);
class Human
{
public:
Human(int a=1,int i=1);
inline int Getage(){return age;};
inline int GetID(){return age;};
RTTI_PRE(Human)
private:
int age;
int ID;
};
////////////////////////////
class Man:public Human
{
public:
Man(int a=1,int i=1,int ifm=1);
RTCT_PRE(Man)
inline int GetMarryStatue(){return ifmarry;};
private:
int ifmarry;
};
///////////////////////////
class Woman:public Human
{
public:
Woman(int a=1,int i=1,int ifm=1);
RTCT_PRE(Woman)
inline int GetMarryStatue(){return ifmarry;};
private:
int ifmarry;
};
//////////////////////////////////
class Child:public Human
{
public:
Child(int a=1,int i=1,int g=1);
RTTI_PRE(Child)
inline int GetGrade(){return grade;};
private:
int grade;
};
//////////////////////////////////
class Baby:public Child
{
public:
Baby(int a=1,int i=1,int g=1,int iq=1);
RTTI_PRE(Baby)
inline int GetIQ(){return IQ;};
private:
int IQ;
};
#endif    UDF.cpp:自己构建的几个类,形成一个以Human类为源头的小框架

#include "UDF.h"
#include <iostream.h>
#include <string.h>
RFX_init::RFX_init(RUNTIMECLASS *newclass)
{
#ifdef R_DEBUG
if(RUNTIMECLASS::First!=NULL)
{cout<<"First_pre"<<"["<<RUNTIMECLASS::First->name<<"]"<<endl;}
else{cout<<"First_pre"<<"NULL"<<endl;}
    #endif
///////////////初始化链表///////////
newclass->next =RUNTIMECLASS::First;
    RUNTIMECLASS::First=newclass;
/////////////////////////
    #ifdef R_DEBUG
cout<<"["<<newclass->name<<"]"<<"LINKED"<<endl;
cout<<"First_"<<"["<<RUNTIMECLASS::First->name<<"]"<<endl;
cout<<"*****************************"<<endl<<endl;
    #endif
}
RUNTIMECLASS* RUNTIMECLASS::First =NULL;
static char Human_p[]="Human";
RUNTIMECLASS Human::Humanclass={Human_p,sizeof(Human),NULL,NULL,NULL};
RFX_init initHuman(&Human::Humanclass);
RUNTIMECLASS* Human::GetRunTimeClass() const
{return &Human::Humanclass;}
Human::Human(int a,int i)
{
cout<<"Human Creat."<<endl;
age=a;
ID=i;
}
Man::Man(int a,int i,int ifm):Human(a,i)
{
cout<<"Man Creat."<<endl;
ifmarry=ifm;
}
Woman::Woman(int a,int i,int ifm):Human(a,i)
{
cout<<"Woman Creat."<<endl;
ifmarry=ifm;
}
Child::Child(int a,int i,int g):Human(a,i)
{
cout<<"Child Creat."<<endl;
grade=g;
}
Baby::Baby(int a,int i,int g,int iq):Child(a,i,g)
{
cout<<"Baby Creat."<<endl;
IQ=iq;
}
Human* RUNTIMECLASS::RTCreat()
{
if(pf_Creat==NULL)
{
cout<<"此子类不支持动态创建。"<<endl;
return NULL;
}
else
{
return (*pf_Creat)();
}
}
int CMP(char s1[],char s2[])
{
int i=0;
if (strlen(s1)!=strlen(s2))
   return 0;
for(;s1!='\0';i++)
{
if(s1!=s2)
   return 0;
}
return 1;
}
RTTI_LINK(Baby,Child)
RTCT_LINK(Man,Human)
RTCT_LINK(Woman,Human)
RTTI_LINK(Child,Human)    main.cpp:通过往这个框架中添加一个类来说明如何使用这些特性

#include <iostream.h>
#include <stdlib.h>
#include "UDF.h"

class Rainyboy:public Baby
{
public:
Rainyboy(int a=1,int i=1,int g=1,int iq=1);
~Rainyboy();
RTCT_PRE(Rainyboy)
};
Rainyboy::Rainyboy(int a,int i,int g,int iq):Baby(a,i,g,iq)
{
cout<<"Rainyboy Creat."<<endl;
}
Rainyboy::~Rainyboy(){cout<<"Rainyboy Broken";};
    RTCT_LINK(Rainyboy,Baby)
int main()
{
RUNTIMECLASS *pnow;
RUNTIMECLASS *pbas;
Human *newp;
char s;
cout<<"**********"<<endl<<"类别目录表"<<endl<<"**********"<<endl;
for(pnow=RUNTIMECLASS::First;pnow!=NULL;pnow=pnow->next)
{
cout<<pnow->name<<"["<<pnow->size<<"]";
for(pbas=pnow->basic;pbas!=NULL;pbas=pbas->basic)
   cout<<"<-"<<pbas->name<<"["<<pbas->size<<"]";
      cout<<endl;
}
cout<<"***********************************"<<endl;
cout<<"动态创建测试,输入要创建的类名:";
cin>>s;
cout<<"***********************************"<<endl;
for(pnow=RUNTIMECLASS::First;pnow!=NULL;pnow=pnow->next)
{
if(CMP(pnow->name,s))
{
   cout<<"Class "<<pnow->name<<"FOUNED!"<<endl;
   newp=pnow->RTCreat();
   break;
}
}
if(pnow==NULL)
cout<<"Class "<<s<<" NOT FOUNED!"<<endl;
delete newp;
return 1;
}
      程序运行之后,显示出这些信息:
      
      输入要创建的类名后,显示:
      
      说明动态创建成功。

      PS:花了些时间写了这个有点长的东西,是因为随着学习Python的推进,觉得很多东西都是似曾相识,是已有技术的另一种实现。因此翻出这些老古董代码,整理自己的思路,就当是抛砖引玉吧,呵呵!

      PS2:《深入浅出MFC》是一本不可多得的好书,今日再读,更觉得它是求知路上不可多得的良师益友,全书四篇:“勿在浮沙筑高台”,“欲善工事先利其器”,“浅出MFC程序设计”,“深入MFC程序设计”,不急不躁,带领读者慢慢品味代码之美,编程之乐,令人流连忘返!

firecat_2 发表于 2010-11-7 22:19

思路清晰 有自己的见解 前途无量

smtmobly 发表于 2010-11-9 17:53

我喜欢python的原因在于它的方便,简洁,内存处理简单,是跨平台的。
你推荐,mfc什么的好像是Microsoft function collection ,微软的东西用了很多年了,现在我

smtmobly 发表于 2010-11-9 17:54

还是建议 楼主 向linux靠拢,原因很简单,一、开源。二、linux结构的紧凑,软件间无缝连接与共享,运行 速度。win7只开一个ie就消 耗了800+M的内存,linux下只有200+M。

Rainyboy 发表于 2010-11-9 23:20

本帖最后由 Rainyboy 于 2010-11-9 23:22 编辑

回复 4 # smtmobly 的帖子

是的,这不遵循兄台的建议学习嘛,有点感想就回来分享了,呵呵。{:{35}:}

smtmobly 发表于 2010-11-10 09:33

呵呵!坚持哈!我回复的时候居然弹出说我有非法信息!郁闷,删了很长一段,才发出这几句

Seventy721 发表于 2011-4-2 03:27

侯的那本《深入浅出》(1998年出版) 里面的精华部分基本雷同于《MFC internals: inside the Microsoft Foundation class architecture》(George Shepherd, Scot Wingo, published by Addison-Wesley, 1996),但是他添了一些例子和花边。两本书我都有,都认真读过,我本科的毕业论文写的就是OOP编程方面的内容。《Effective C++》和《More Effective C++》都是非常好的书。我曾经想做一个C++程序员,但是后来逐渐觉得没意思。计算机语言不过是实现思想的工具,计算机程序只是客观世界的反映,关键的问题是那个思想是什么,客观世界的规律是什么。因此我去读了个PhD。现在我觉得很愉快。

Rainyboy 发表于 2011-4-2 08:56

回复 7 # Seventy721 的帖子

呵呵,我也差不多吧,论坛上的wqsong,fircat_2和我大概和你都有相似的经历吧,现在你是PHD,wqsong现在研究流体,fircat_2在搞故障诊断,这大概就是大家用来建立在变成这套手艺上的“思想”和对“规律”的探索吧。

Seventy721 发表于 2011-4-2 13:16

回复 8 # Rainyboy 的帖子

下次我回北京一定要找你聊聊。
页: [1]
查看完整版本: 关于OOP中若干特性的思考