博文

ATL布幔之下的秘密(2)(2007-10-05 14:19:00)

摘要:作者:Zeeshan Amjad
译者:李马 (home.nuc.edu.cn/~titilima )
原文出处: http://www.codeproject.com/atl/atl_underthehood_2.asp 介绍
   在本系列的教程中,我要讨论一些ATL的内部工作方式以及它所使用的技术,这是本系列的第二篇文章。

   现在让我们来探究一些虚函数背后更加有趣的资料。为了和上文保持一致,在本文的讨论中我将使用相同的顺序,程序的序号从20开始。
   让我们看看下面这个程序:
程序20. #include <iostream>using namespace std;class Base {public: virtual void fun() { cout << "Base::fun" << endl; } void show() { fun(); }};class Drive : public Base {public: virtual void fun() { cout << "Drive::fun" << endl; }};int main() { Drive d; d.show(); return 0;}程序的输出为:Drive::fun这个程序清楚地示范了基类的函数是如何调用派生类的虚函数的。这一技术被用于不同的框架中,例如MFC和设计模式(比如Template Design Pattern)。现在你可以修改一下这个程序来看看它的行为,我将要在基类的构造函数中调用虚函数,而不是普通的成员函数。

程序21.
#include <iostream>using namespace std;class Base {public: Base() { fun(); } virtual void fun() { cout << "Base::fun" << endl; }};class Drive : public Base {public......

阅读全文(3095) | 评论:0

ATL布幔之下的秘密(1) (2007-10-05 14:18:00)

摘要:作者:Zeeshan Amjad
译者:李马 (home.nuc.edu.cn/~titilima )
原文出处: http://www.codeproject.com/atl/atl_underthehood_.asp 介绍
   在本系列的教程中,我要讨论一些ATL的内部工作方式以及它所使用的技术。
   在讨论的开始,让我们先看看一个程序的内存分布。首先,编写一个简单的程序,它没有任何的数据成员,你可以看看它的内存结构。
程序1. #include <iostream>using namespace std;class Class {};int main() { Class objClass; cout << "Size of object is = " << sizeof(objClass) << endl; cout << "Address of object is = " << &objClass << endl; return 0;}这个程序的输出为:Size of object is = 1Address of object is = 0012FF7C现在,如果我们向类中添加一些数据成员,那么这个类的大小就会是各个成员的大小之和。对于模板,也依然是这样:
程序2.#include <iostream>using namespace std;template <typename T>class CPoint {public: T m_x; T m_y;};int main() { CPoint<int> objPoint; cout << "Size of object is = " << sizeof(objPoint) << endl; cout << "Address of object is = " << &objPoint << endl; return 0;}现在程序的输出为:Size of object is = 8Address of object is = 00......

阅读全文(2499) | 评论:0

[转] C++0x设计之路(2007-10-02 14:39:00)

摘要:C++0x设计之路  ————把握现在 展望未来                                                  [著] Bjarne Stroustrup                                                                 [译]firingme [译者注:原文地址:http://www.research.att.com/~bs/rules.pdf] 每隔一两天,我都会收到关于改进C++的e-mail建议。很多建议如果真的能够成为语言或者标准库的一部分将是一件不错的事情,会让很多程序员深受其益。当然,综合来看,这些建议有很多重复之处,因此,也可以说,在我提出的列表中仅有上百个建议而已——具体的数量取决于你对“相关建议”这个概念的定义。人们希望改进的语言特性的一份不完全列表在 http://www.research.att.com/~bs......

阅读全文(4214) | 评论:0

[转] C++ 0x 里的垃圾收集器(2007-10-02 14:37:00)

摘要:好像最近C++标准地下工会在公司附近开会,所以我们上班时偶尔可以看到工会成员矫健的身影。我们也近水楼台,得以听到关于C++0x进展的一些科普报告。上次Bjarne Stroustrup做了关于泛型编程的讲座后,Symantec实验室的Michael Spertus也做了一个关于C++ 0x里垃圾收集的讲座。Michael Spertus当年写出了IBM PC上最早的C编译器,也是C++ 0x里垃圾收集器的主要倡议人。       Michael从什么是GC开始讲起。三言两语后,谈到在C++ 0x里加入GC的动机。一是许多数据结构,对象,或者资源的生命期难以事先确定、静态管理。我们需要某种形式的动态管理技术。很多老大以为C++高手的标志之一是不需要GC。如果这样想,Unreal的Tim Sweeney就笑了。Unreal引擎里就大量使用GC。如果一个系统需要管理大量对象,要求高吞吐量,但可以容忍偶尔的系统延迟的话,GC是颇为不错的工具。所以3D/建模,2D图像处理等计算都可以用到GC。第二个理由非常有煽动力:帮助C++程序清除内存泄露。我们不必在C++里排斥人肉内存管理。问题是,人肉内存管理难以尽善尽美。大型系统里内存泄露几乎不可避免。每次泄露也不多,10来KB到几个MB。但积累起来,也就造成诸多问题。因为每次泄露量不大,也不像Java等基于GC的语言,“泄露”随时都在发生。所以可以通过定期执行GC来清除这些泄露,也不用消耗过多资源。Michael后来举了一个颇有说服力的例子:某电信公司的交换机,100多万行程序,有持续的内存泄露。每小时必须重启一次。使用GC后,内存泄露消失,交换机不用再定时重启。重启时系统堆上有大概200个线程,500MB内存。这样算来,每线程每小时泄露2.5M。每线程每分钟不过42KB。而每分钟收集42KB内存对系统根本不会有什么影响。最后实测下来,收集500MB不过需要两秒种。分摊到一个小时内,完全可以忽略不计。这样的GC应该叫LC—Litter Collector。还有一个例子是Michael向Mozilla浏览器里注入GC。每次用户操作使得GC回收大概10KB的内存,实在是小菜一碟。       Michael接着谈到C++ GC的发展。C++ GC已经......

阅读全文(2730) | 评论:0

[转] C++的进化:C++0x一瞥(2007-10-02 14:36:00)

摘要:摘要:C++标准委员会近年来一直在为下一代C++标准的制定而努力着,本文介绍了几个很可能成为下一代标准的新特性,包括generalized initialization,concept,move semantics,auto/delctype,让大家先睹为快。 1. 什么是C++0x     很简单,0x代表21世纪的第一个十年中的某一年,可能是07也可能是09,这要视标准出台的具体时间而定(但放心,不会是99),这也意味着新标准出台的时间不会太遥远了。 2. 新特性     这里我只打算从直观的角度介绍每一个新特性,关于每一个特性都可以在“C++ Standards Committee Papers”找到相应的论文。 2.1 Generalized Initialization     描述:支持将形如{1,2,3}的initializer作为参数进行传递
    意义:相信你一定写过这样的代码吧:         vector <int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);     有了上述机制,只要给vector多加一个initializer为参数的构造函数,代码就可以简化为:         vector <int> v = {1,2,3}; 世界本应如此简单,不是吗。 2.2 Concept     描述:从语言层面支持STL的concept概念
    如下代码定义了一个EqualityComparable的conc......

阅读全文(2941) | 评论:0

附录:进程间通讯(2007-09-26 19:06:00)

摘要:附录:进程间通讯 一、说明进程间通讯的必要性及困难性 二、Socket的方法,对于不同机器上且数据量很的情况会有很大的帮助,但对于同一台机器之间的不同进程之间的通讯就不方便了 (代码量太多) 三、进程间通讯的剪切板方法 a、对于发送端:        CString str;        GetDlgItemText(IDC_EDIT1,str);        HANDLE hGlobal;        if(this->OpenClipboard())//获取剪切板的资源所有权        {               EmptyClipboard();//将剪切板的内容清空               hGlobal=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//在堆上分配一块用于存放数据的空间,程序返回一个内存句柄               char* pBuf=(char*)GlobalLock(hGlobal);//将内存块句柄转化成一个指针,并将相应的引用计数器加一               strcpy(pBuf,str.GetBuffer(str.GetLength()));//将字符串拷入指定的内存块中     ......

阅读全文(9063) | 评论:0

第二十课:勾子及数据库访问(2007-09-26 19:05:00)

摘要:第二十课:勾子及数据库访问 本讲主要内容: 第一部分:勾子 1、  回忆第一讲内容:(操作系统与应用程序的关系)由如果想从中间控制应用程序的消息,应该从哪入手?(如果把以高速公路上的汽车比作消息,以检查流串犯为例引出需要在检查站处设岗)从而引入勾子的概念,从而讲到勾子链(后挂的排在勾子链上的前面) 2、  函数的讲解(SetWindowsHookEx()与UnHookWindowHookEx())设一个勾子也只是调用一个API函数SetWindowsHookEx()函数,要想取消勾子的作用就要卸掉勾子,可以使用如下API函数UnhookWindowsHookEx()函数。(例子:在一个exe文件中实现一个简单的勾子,以处理回车键为例(VK_RETURN)) 2、在一个DLL文件中实现同上的一个简单的勾子(void setHook()、void UnHook()、setWindowsHookEx(WH_KEYBOARD,::GetModuleHandle(“HookDll”),GetCurrentThreadID())) 3、在一个DLL文件中实现一个系统级别的勾子(将线程号改为0)(此时可以用窃取别人密码为例子来讲) 3、  在一个EXE文件中实现一个自动启动全屏的应用程序并带一个DLL勾子 a、新建一个基于对话框的工程,去掉对话框类及相应的文件 b、从CWnd继承一个新类,实现其WM_PAINT消息响应函数 c、在InitInstance()中加入如下代码创建主窗口   CString ClassName=::AfxRegisterWndClass(0,0,(HBRUSH)::GetStockObject( WHITE_BRUSH),0);   m_FullWnd.Create(ClassName,"",WS_CHILD,CRect(0,0,0,0),CWnd::GetDesktopWindow(),1);   m_FullWnd.SetWindowPos(&CWnd::wndTopMost,0,0,::GetSystemMetrics(SM_CXSCREEN),::GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW); &nbs......

阅读全文(9402) | 评论:1

第十九课:ActiveX控件(2007-09-26 19:04:00)

摘要:第十九课:ActiveX控件 本讲主要内容: 1、  首先认识什么叫ActiveX控件(VB演示MonthView控件与DatePicker控件) 演示一下在VB下的如何得到DTPicker下的日期内容及星期的内容,进而讲到属性,除了属性外还有方法和事件、属性页依次演示。 2、  VB中是很方便的,要是在VC中也能用就好了,开始在VC中演示如何使用ActiveX控件。同上一例子。(更进一步讲到属性、方法、事件的概念及容器与控件之间的关系等概念)演示如何得到日期的各个部分的内容。在此要讲到变体类型的变量(VARIANT结构及CComVariant类型及_variant_t类型的区别与联系) 3、  ActiveX控件中使用的技术分析,为了保证在各种开发工具上都能使用,对于在其内容实现时会有一些具体的要求。(字符串要使用(BSTR),颜色OLE_CORLOR,变体类型) 4、  注册与反注册(Regsvr32.exe工具的使用) 5、  创建一个ActiveX控件的方法,及常用工具的比较 6、  自动动手写一个时钟控件(工具介绍及常用选项说明及向导生成代码分析) 7、  修改图标 8、  在OnDraw中增加控件外观代码如下:(注意颜色转换的问题) CBrush br; br.CreateSolidBrush(TranslateColor(GetBackColor())); pdc->FillRect(rcBounds,&br); CTime tm=CTime::GetCurrentTime(); CString str=tm.Format("%H:%M:%S"); pdc->SetBkMode(TRANSPARENT); pdc->SetTextColor(TranslateColor(GetForeColor())); pdc->TextOut(0,0,str); 9、  解决不能自动更新的问题 a)         为控件响应WM_CREATE和WM_TIMER事件 b)    &nb......

阅读全文(9176) | 评论:1

第十八课:动态链接库(2007-09-26 19:03:00)

摘要:第十八课:动态链接库 一、概念: 1、  静态链接库: 应用程序从函数库中得到所的函数的执行代码,然后把招生代码自身的执行文件中,应用程序在运行时,不再需要函数库的支持。 2、  动态链接库: 应用程序的中不包含函数库中的函数的执行代码,编译和连接时只是包含包含它们的参考,运行时再将它们的执行代码加入内存,所以在程序运行时需要函数的支持。 二、编写DLL: 建立一个Windows Dynamic-Link Library,选择建一个An Empty Dll Project,加入一个CPP文件, int add(int x,int y) { return x+y; } extern "C" _declspec (dllexport) int add3(int x,int y,int z) {         return add(x,y)+z; } 说明: 1.  Add是一个供DLL中其它函数调用的函数, Add3是DLL提供给其它应用程序调用的函数。 2.  当DLL中含有输出函数时,编译DLL时会生成DLL文件和LIB文件。LIB文件称为DLL的导入库,它是一个特殊的库文件。它不包含执行代码,只是用来提供给链接器关于DLL函数在DLL中的入口信息,从而使得可执行程序 中也不会包含所调用DLL函数 的代码 ,只保留对DLL函数的动态链接参考。 3.  导出函数的两种方法: a.  使用微软专用的_declspec (dllexport):(如上面的例子) cpp文件在编译为OBJ文件时要对函数进行重新命名,C语言会把函数name重新命名为_name,而C++会重新命名为_name@@decoration, extern "C"表示用C语言的格式将函数重命名。 b.  使用模块定义文件: 模块定义文件即DEF文件,是包含一个或多个模块定义语句的文本文件,用来描述动态链接库的各种属性。 一个最小的·DEF文件包括以下模块定义语句: l         第一条语句必须是LIBRARY语句,用来说明动态......

阅读全文(9130) | 评论:0

第十七课:多线程(2007-09-26 19:02:00)

摘要:第十七课:多线程 一、概念: 进程:一个进程就是一个运行的程序,它有独立的内存、文件句柄和其他系统资源。当启动一个进程时,操作系统会为此进程建立一个4GB的地址空间,进程是操作系统分配内存地址空间的单位。 线程:是操作系统分配处理器时间的最基本单元。所以一个进程必须包含一个线程,我们称之为主线程。如果需要,进程可以产生更多的线程,让CPU在同一时间执行 不同段落的代码。 二、举例: 1.  在单线程中执行多个死循环: 建立一个控制台工程,加入一个cpp文件,编写如下代码: #include "stdio.h" void fun() {     while(1)     {         printf("thread 2 is rurnning!\n");     } } void main() {     fun();     while(1)     {         printf("thread 1 is running!\n");     } } 此时只能打出thread 2 is rurnning!,因为CPU总是在执行fun函数的代码 。没有机会向下执行其余代码。 2.  在单线程中执行多个死循环: #include "stdio.h" #include "windows.h" DWORD WINAPI fun(LPVOID lpParameter) {     while(1)     {         printf("thread 2 is rurnning!\n");     } } void main() { CreateThread(NULL,0,f......

阅读全文(9326) | 评论:0