Dynamic Creation动态创建的疑惑。

dianhui 2009-11-17 07:17:21
今天在看候的深入浅出第三章动态创建时晕了!没太看明白。
首先对这一章研究目的我就没太看明白。比如就这个题目:动态创建
什么是动态创建,不明白,然后网上一查,很多网友解释就是:用一个类名,然后new出一个实例来就是动态创建,也就是说:比如我们定义一个类如下:
class Cbook
{
Cbook::Cbook();
name;
.
.
};

然后我在程序中这样:
Cbook myBook=new Cbook;
网友的意思就是指上面这个new Cbook就是动态创建。
看到这里我就晕了,候先生在解说这动态创建时,就讲到了一个CRuntimeClass的类,这个类中用到一个函数叫:CreateObject();
事实上,IMPLEMENT_DYNCREATE宏在展开时,我们可以看
..CreateObject()
{return new CFrameWnd}//原书实例。
其中就有一个new加上一类名CFrameWnd,如果像网友所说:new+类名 来创建对像就是动态创建,那这个IMPLEMENT_DYNCREATE不是多此一举了么。直接在代码中用new CFrameWnd来动态创建就行了,还要这个宏干什么。
而候先生是用一个这样的实例来解释动态创建的:
其实就是一个CRuntimeClass链,利用CRuntimeClass指针,调用CreateObject函数,来创建指定类名的实例来描述了动态创建,并不像网友所说的用一个new加上一个类名就是动态创建,如果一个new加上一个类名就是动态创建,那候先生第三章有关动态创建的内容在我看来就真是不知所云了。

希望有高手能给在下指点指点,让我明白这个动态创建和DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE这对宏的意思和用途。
...全文
282 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
qiangorqiang 2009-11-25
  • 打赏
  • 举报
回复
说简单一些就是让程序可以用字符串形式的类名来创建对象。
liguangqang 2009-11-25
  • 打赏
  • 举报
回复
pClass=RUNTIME_CLASS(CXXObject); 中的 CXXObject 这个不是关键是不采用类型识别编译器就会出错
实际是用宏的方式加入到一个字符串中,形成新的字符串来检索类型表,找到最终的类再动态创建出来的。
liguangqang 2009-11-25
  • 打赏
  • 举报
回复
动态创建和运行时类型识别是有关联的,有些时候运行时只知道这个类名,不可能直接通过字符串来创建类的实例,注意这是在程序运行时。所以ms框架将大部分类做成了一个运行时网,通过字符串来识别出是哪个类型后然后再动态创建出来。这和new的最大不同是提供了一个类字符串和类型的映射。这个字符串是通过宏的方式加进去的。
瓶盒 2009-11-23
  • 打赏
  • 举报
回复
今天跟了一下MFC框架的建立过程,有点收获,与楼主共享一下。
以一个单文档项目CsingleDoc为例。
框架模板对象的建立在主程序对象CsingleDocApp::InitInstance()中,如下
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CsingleDocDoc),
RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口
RUNTIME_CLASS(CsingleDocView));
我们只看文档对象CsingleDocDoc的建立过程,上面这句代码建立了一个模板对象pDocTemplate ,同时令
pDocTemplate ::m_pDocClass = RUNTIME_CLASS(CsingleDocDoc);
即pDocTemplate ::m_pDocClass =(CRuntimeClass*)CsingleDocDoc::classCsingleDocDoc;
这是CsingleDocDoc类所拥有的一个静态成员变量。
接着会调用if (!ProcessShellCommand(cmdInfo)),这句代码才会新建一个我们自定义的CsingleDocDoc对象。具体建立的代码在doctempl.cpp中
CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();
这里的m_pDocClass由于是CsingleDocDoc的运行时类,所以实际上就会去调用CsingleDocDoc::CreateObject();
也即 return new CsingleDocDoc;
楼主所不明白的就是这里为何不直接用CDocument* pDocument = (CDocument*)new CsingleDocDoc;
这里需要清楚,这句代码是在doctempl.cpp中,而doctempl.cpp中的代码属于MFC的库文件代码,已经预编绎成了lib文件,再MFC项目编译时直接附加(静态链接)或调用(动态链接)。
应该说MFC的动态运行时的思想,已经蕴育了COM的构建与执行相分离的思想。
artcpp 2009-11-21
  • 打赏
  • 举报
回复
...
jameshooo 2009-11-21
  • 打赏
  • 举报
回复
你还是没理解编译期和运行期的不同。

MFC框架已经做死了,它认识的类只有有限的数量,例如CObject/CWnd/CView/CDialog/CFrameWnd...,它怎么认识你派生的CXXObject呢?既然不认识,又怎么去new呢?难道一段二进制代码还能调用"new CXXObject"这种字符串指令?
要理解这种区别其实很简单,你自己设计一套框架,允许第三方扩展从你的基类派生,然后让你创建第三方派生类实例,你该怎么做?调用new CXXXExt?问题是你连这些派生类的名字都不知道,何况是在运行时创建。
icefairy 2009-11-21
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 dianhui 的回复:]
感谢楼上这么多朋友,已经让我能所理悟了!
现在,再向大家问一网友的回答:
DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE宏,动态创建就是指能够使你的类通过这样的方法创建:
pClass=RUNTIME_CLASS(CXXObject);
CObject * pObject=pClass->CreateObject();
上面这个就是指动态创建,那我想问下,难道我就不能直接用下面这条语代替上面两条代码么?
CObject * pObject= new CXXObject;
这样不是与上面效果一样的吗?这不一条语句也完成了动态创建了吗?
[/Quote]

不一样啊,pClass=RUNTIME_CLASS(CXXObject);
相当于CObject * pObject= new CXXObject; 之外 还创建了一个类 书上写的比较清楚了
然后 还要create 。

dianhui 2009-11-21
  • 打赏
  • 举报
回复
up
dianhui 2009-11-20
  • 打赏
  • 举报
回复
感谢楼上这么多朋友,已经让我能所理悟了!
现在,再向大家问一网友的回答:
DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE宏,动态创建就是指能够使你的类通过这样的方法创建:
pClass=RUNTIME_CLASS(CXXObject);
CObject * pObject=pClass->CreateObject();

上面这个就是指动态创建,那我想问下,难道我就不能直接用下面这条语代替上面两条代码么?
CObject * pObject= new CXXObject;
这样不是与上面效果一样的吗?这不一条语句也完成了动态创建了吗?
liumenghappy 2009-11-20
  • 打赏
  • 举报
回复
1、宏IMPLEMENT_DYNCREATE本质上也是用的new,你仔细看看IMPLEMENT_DYNCREATE就明白了
2、可以说,DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE是可以用new来替代的,它们都是动态创建
3、深入浅出第三章指出,用DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE好处就是:读一个文档时,读到Cbook类,需要创建一个Cbook 类,这时直接用new显然是不行的,因为Cbook在这里只是一个字符串,计算机不可能知道它是一个类,但这时使用DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE就可以直接创建一个Cbook,很方便。但是,并不是说这里非要用DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE,深入浅出第三章又指出,可以通过判断字符串Cbook与程序里的某个类名是否相同,如果程序中有个类的名称是Cbook,那么我们直接用new来动态创建这个类就行了!乍一看觉得DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE是多余的,先判断字符串是否是类名然后用new动态创建不就行了吗,干嘛弄个那么复杂的宏呢?这里就要考虑一个新的问题,假如程序中用很多类,就说100个吧,那你是不是要判断100次,而且每次新建类之前都要判断100次,这样做显然不是MFC想要的,所以,DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE是必要的
4、这个问题在《深入浅出MFC》的后面几章还会有讲解,相信看到那里你要完全明白了。
bulijun1987 2009-11-19
  • 打赏
  • 举报
回复
动态创建就是给定一个名字就可以创建一个相应的对象,
这个名字可以是从文件中读出来的,
underuwing 2009-11-19
  • 打赏
  • 举报
回复
我把我的理解说一说吧。首先你得理解什么是动态识别,动态识别就是说在运行时可以知道一个对象属于哪个类。区别进程可以用进程id,区别窗口可以用窗口句柄。要区别类的话,就只能用类的静态成员了,因为不管类有多少个对象,他们都共用一个静态成员。我们可以给类安排一个静态成员变量,用以识别对象属于哪个类。下面是一个最简单的类型识别例子。
#include <iostream>
using namespace std;
class CBoy
{
public:
const int * GetRunTimeClass(){return & classCBoy;}
static const int classCBoy;
};
const int CBoy::classCBoy=1;
class CGirl
{
public:
const int * GetRunTimeClass(){return & classCGirl;}
static const int classCGirl;
};
const int CGirl::classCGirl=1;
void main()
{
CGirl student;
if(student.GetRunTimeClass()==&CGirl::classCGirl)
cout<<"a girl\n";
else if(student.GetRunTimeClass()==&CBoy::classCBoy)
cout<<"a boy\n";
else
cout<<"unkonwen\n";
system("pause");
}

里面的classCBOY和classCGIRL两个静态成员变量就是唯一的识别标识。可以用它来识别student对象属于哪个类。
而在实际中,我们不用int型的静态成员来识别,而是用一个有更多含义的结构体静态成员来作为类的识别标识。我们叫他CRuntimeClass。
这个结构体里面,又有很多数据成员和函数成员。数据成员可以用来表示该类的名称,大小,版本号什么的。这个结构体里面有一个函数成员非常重要,可能也是你迷糊的地方,就是CreateObject()函数。
而动态创建呢,根据我的理解就是用一个CRuntimeClass类型指针得这个CRuntimeClass静态成员的地址,然后调用CreateObject()函数,来创建对象。至于哪个CRunTimeClass链表也是结构体里面的一个数据成员,我还不太明白他的作用。
underuwing 2009-11-19
  • 打赏
  • 举报
回复
这个问题,王艳平的windows程序设计第五章框架管理基础里面讲的挺好的。可惜,我正在看这一章,还没有完全明白,不能回答你。
dianhui 2009-11-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 jameshooo 的回复:]
MFC框架是已经固定的,它内部的所有类也是固定的,现在想让框架创建出你的自定义派生类实例,你自己想想该怎么创建?这就是动态创建的目的。

new一个类是编译器才理解的指令,在编译的二进制代码中被翻译成了分配内存+调用构造函数的指令,所以运行期是不存在new指令的,你让框架怎么创建出你的类?动态创建的原理就是每个自定义派生类提供一个静态函数用来创建自己,然后把这个静态函数的指针放到运行时类中保存起来,而每个类在运行时类链表中占用一个节点,运行时类链表全局只有一个,由MFC管理,这个全局实例保存在模块数据中,每个EXE/DLL模块都有一个属于自己的模块数据。

MFC框架动态创建外部派生类的过程:
1、遍历所有已加载的模块(EXE/DLL)
2、在每个模块中找到它的模块数据
3、从模块数据中获取该模块的运行时类链表
4、在运行时类链表中遍历所有登记的运行时类数据,根据类名确定是否找到了
5、如果找到了运行时类,调用它的创建函数成员(前面说过的静态函数),这样就完成了类的创建。
[/Quote]

感谢……
再让我琢磨一下结贴。
cnzdgs 2009-11-18
  • 打赏
  • 举报
回复
很多时候程序要构造一个对象,而对象的类名在编程时是不确定的,只有在运行过程中才能知道,这种情况就需要动态构造。
jameshooo 2009-11-18
  • 打赏
  • 举报
回复
MFC框架是已经固定的,它内部的所有类也是固定的,现在想让框架创建出你的自定义派生类实例,你自己想想该怎么创建?这就是动态创建的目的。

new一个类是编译器才理解的指令,在编译的二进制代码中被翻译成了分配内存+调用构造函数的指令,所以运行期是不存在new指令的,你让框架怎么创建出你的类?动态创建的原理就是每个自定义派生类提供一个静态函数用来创建自己,然后把这个静态函数的指针放到运行时类中保存起来,而每个类在运行时类链表中占用一个节点,运行时类链表全局只有一个,由MFC管理,这个全局实例保存在模块数据中,每个EXE/DLL模块都有一个属于自己的模块数据。

MFC框架动态创建外部派生类的过程:
1、遍历所有已加载的模块(EXE/DLL)
2、在每个模块中找到它的模块数据
3、从模块数据中获取该模块的运行时类链表
4、在运行时类链表中遍历所有登记的运行时类数据,根据类名确定是否找到了
5、如果找到了运行时类,调用它的创建函数成员(前面说过的静态函数),这样就完成了类的创建。
wocow3 2009-11-18
  • 打赏
  • 举报
回复
http://topic.csdn.net/u/20090308/14/99D6EADC-B8D3-4CCF-8308-EEB8E557C2C5.html
瓶盒 2009-11-18
  • 打赏
  • 举报
回复
楼上说的很透,以我理解的方式举个例。
比如你定义了一个类Cbook :public CFrameWnd
这个类是基于CFrameWnd的,在MFC程序中,它是不能由你自已通过new的方式建立的。在你建立一个文档类的项目时,MFC会自动替你建立能按文档方式运行的基本代码,代码中必然要包含了一个CFrameWnd类对象的建立,但这个类是你要派生自定义的,自动建立的代码显然不可能用m_pMainWnd=new CFrameWnd()的方式建立你定义的类。所以用m_pMainWnd=(运行时类名)::CreateObject();的方式来建立对象。这个(运行时类名)估计是编译的时候变成你的Cbook,这点我还不确定,等高手来确证下。
zhp21 2009-11-18
  • 打赏
  • 举报
回复
随便写个例子
#define CREATE_OBJ(CLASSNAME) CLASSNAME* CreateObj(CLASSNAME)
#define CreateObj(className) Create##CLASSNAME()


调用CREATE_OBJ(ICa )
就是 ICa* CreateICa();

那么如果ICa的类工厂的话。 那么CREATE_OBJ所谓动态创建对象就是 其实MFC 很多地方利用 宏定义,##连结做的那些消息机制什么的,运行时什么的 , 开个别机制源码就不用看深入浅出那破书了
  • 打赏
  • 举报
回复
IMPLEMENT_DYNCREATE

  IMPLEMENT_DYNCREATE(class_name,base_class_name)

  说明:

  通过DECLARE_DYNCREATE宏来使用IMPLEMENT_DYNCREATE宏,以允许CObject派生类对象在运行时自动建立。主机使用此功能自动建立对象,例如,但它在串行化过程中从磁盘读去一个对象时,他在类工具里加入IMPLEMENT_DYNCREATE宏。若用户使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏,那么接着使用RUNTIME_CLASS宏和CObject::IsKindOf成员函数以在运行时确定对象类。若declare_dyncreate包含在定义中,那么IMPLEMENT_DYNCREATE必须包含在类工具中。
加载更多回复(1)

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧