??xml version="1.0" encoding="utf-8" standalone="yes"?>久久A级毛片免费观看,国产一区二区精品久久岳,婷婷久久久亚洲欧洲日产国码AV http://www.shnenglu.com/richardzeng/category/1011.htmlVC++ 斚w~程文章zh-cnMon, 19 May 2008 22:23:26 GMTMon, 19 May 2008 22:23:26 GMT60Windows GDI CDC 使用问题http://www.shnenglu.com/richardzeng/archive/2006/07/16/10112.htmlBeginning to ~程Beginning to ~程Sat, 15 Jul 2006 19:06:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/07/16/10112.htmlhttp://www.shnenglu.com/richardzeng/comments/10112.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/07/16/10112.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/10112.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/10112.html最q在学习Hoops   的引擎(http://www.hoops3d.com )

模拟它的MVO架构Q不q没有原代码Q所以很难a
设计了一个交互绘囑֟本类Q?br />但是q有错误Q鼠标左键点M?br /> winGDI.cpp中出错?br />请大虾指教一二?br />我已l在q个问题上花了很多的心思?br />其中最重要的就是Painter抽象cȝ设计
他的子类QBufferDCl承CDC
而SGView包含Painter指针Q方便在SGView ::drawEntity调用?br />


SGObject - 对象的抽象类Q也是几何对象
SGModel- 负责对象理Q没有实现所有的功能Q准备用SceneTree来实?br />SGView - 负责昄SGModel中的数据Q关键的函数
void SGView::drawEntity(SGObject* pObj)
{
   pObj->draw(m_pPainter,this)
}

Painter - 装CDC的功?见代?br />
在CSGView创徏的时候创建Painter对象
很可能这里有问题Q!Q!Q?br />void CSGView::OnCreate(..)
{
     CDC* pDC = GetDC();
   Painter* painter = new QBufferDC(pDC);
   m_pSGView->setPainter(painter);
}


MFC 相关的Document/View架构
CSGDocument - 理SGModel

CSGView - 和SGView建立联系Qƈ负责把windows的消息发送给SGView
见原代码

SGActionManager - 负责工具的管?br />SGBaseAction - 工具的抽象基c?br />SGActionDrawLine - l制直线的工?br />


源代码连接:
http://www.shnenglu.com/Files/richardzeng/MVOTest.rar



Beginning to ~程 2006-07-16 03:06 发表评论
]]>
资源和资源管理类的设计问?/title><link>http://www.shnenglu.com/richardzeng/archive/2006/05/27/7741.html</link><dc:creator>Beginning to ~程</dc:creator><author>Beginning to ~程</author><pubDate>Sat, 27 May 2006 14:19:00 GMT</pubDate><guid>http://www.shnenglu.com/richardzeng/archive/2006/05/27/7741.html</guid><wfw:comment>http://www.shnenglu.com/richardzeng/comments/7741.html</wfw:comment><comments>http://www.shnenglu.com/richardzeng/archive/2006/05/27/7741.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/richardzeng/comments/commentRss/7741.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/richardzeng/services/trackbacks/7741.html</trackback:ping><description><![CDATA[ <p> <br />我要设计的应用程序其中的一个模块就是封?windows GDI中的ȝQ画LGDI object<br />把GDI object 再封装成resourceQ以实现多种样式多线条的ȝ及画刯?/p> <p>ȝQ画L资源l承resource<br />Z避免发生资源泄露和resource的管?br />设计ResourceManagerc,负责资源的创建,加蝲和卸载以及删?/p> <p>两个抽象c?Resource ?ResourceManager<br />两个具体c?ConcreateResource ?ConcreateResourceManager<br />分别z于上面的抽象c?/p> <p>以上设计是看?OGRE 游戏引擎的资源管理部分,<br />对它的资源管理类ResourceManager不是很理?/p> <p>resource z了pen,brush{类<br />pencd以来自文Ӟ也可以自己创建SubPen d到SubPenList?/p> <p>ResourceManager 负责创徏资源Resource<br />1. 如果我在抽象?ResourceManager 声明 createRes函数Qƈq回基类resource<br />势必会要强制转换Q然后在用到具体的Resource时候又要{换回?/p> <p>2. 如果我在具体c?ConcreateResourceManager 声明 createConcreateRes函数<br />那么q费了我应用设计模式设计这么多c?/p> <p> <br />// abstract class for resource<br />class Resource{<br />public:<br /> // standard constructor<br />  Resource(const string& name, const string& group)<br /> :mName(name),mGroup(group){}<br />  ~Resource(){}<br />protected:<br /> // prevent default construct<br />  Resource():mName(""),mGroup(""){}<br />  string mName;<br />  string mGroup;<br />  static unsigned long mHandle;<br />};</p> <p>// subclass of resource<br />// concreateResource such as PEN<br />class Pen:<br /> public Resource{<br /> Pen(const string& name, const string& group)<br />  :Resource(name,group){}<br />  ~Pen(){}<br /><br />  void loadfromFile(string& filename);<br /><br />// add into vector<br />  void addSubPen(SubPen* sub){<br />     mSubPenList.push_back(sub);<br />}<br />public:<br />typedef std::vector<SubPen> SubPenList;<br />SubPenList mSubPenList;</p> <p>};<br />class <br />// abstract class for resource manager<br />class ResourceManager{<br />public:<br />  ResourceManager(){}<br />  ~ResourceManager(){}<br />public:<br />// here , I cannot understand OGRE degsin<br />  Resource* createRes(const string& name,const string& group);<br /> // resource map <br /> typedef std::map<string,Resource*> ResourceMap;<br />   ResourceMap mResources;</p> <p>};</p> <p>// subclass ResourceManager<br />class ConcreateResourceManager<br /> :public ResourceManager<br />{<br /> ConcreateResourceManager(){}<br /> ~ConcreateResourceManager(){}</p> <p>      // how can design here!!<br />       Pen* createPen(const string& name,const string& group){}<br />}</p> <p> </p> <img src ="http://www.shnenglu.com/richardzeng/aggbug/7741.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/richardzeng/" target="_blank">Beginning to ~程</a> 2006-05-27 22:19 <a href="http://www.shnenglu.com/richardzeng/archive/2006/05/27/7741.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++中Singleton的实现[zhuan]http://www.shnenglu.com/richardzeng/archive/2006/04/21/5999.htmlBeginning to ~程Beginning to ~程Fri, 21 Apr 2006 01:31:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/04/21/5999.htmlhttp://www.shnenglu.com/richardzeng/comments/5999.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/04/21/5999.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/5999.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/5999.html
q些东西在网上都很多了,但是我觉得他们的使用都不W合我的要求Q所以自己动手丰衣食,写一个自p用的Q够用就好?/div>
#include <iostream>
 
using namespace std;
 
//单g模板c?/div>
template<typename T> class Singleton
{
protected:
 
  static T* m_Instance;
 
  Singleton(){}
  virtual~Singleton(){}
 
public:
 
  //实例的获?/div>
  static T* Instance()
  {
    if(m_Instance==0)
      m_Instance=new T;
 
    return m_Instance;
  }
 
  //单gcȝ释放
  virtual void Release()
  {
    if(m_Instance!=0)
    {
      delete m_Instance;
      m_Instance=0;
    }
  }
};
 
//单g模板试c?/div>
class Test:public Singleton<Test>
{
  friend class Singleton<Test>; //声明为友员,不然会出?/div>
protected:
  Test()
  {
    a=b=c=0;
  }
  virtual ~Test(){}
 
public :
 
  int a;
  int b;
  int c;
};
 
//初始化静态成员。。?/div>
template<> Test*Singleton<Test>::m_Instance=0;
 
 
//以下为测试代?/div>
void main()
{
  Test*t=Test::Instance();
 
  t->a=5;
  t->b=25;
  t->c=35;
  cout<<"t: a="<<t->a<<" b="<<t->b<<" c="<<t->c<<endl;
 
  Test*t2;
  t2=Test::Instance();
  cout<<"t2 a="<<t2->a<<" b="<<t2->b<<" c="<<t2->c<<endl;
 
  t2->Release();
}


Beginning to ~程 2006-04-21 09:31 发表评论
]]>
波Ş昄不是很难 /zhuanhttp://www.shnenglu.com/richardzeng/archive/2006/03/16/4229.htmlBeginning to ~程Beginning to ~程Thu, 16 Mar 2006 03:00:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/16/4229.htmlhttp://www.shnenglu.com/richardzeng/comments/4229.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/16/4229.html#Feedback1http://www.shnenglu.com/richardzeng/comments/commentRss/4229.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/4229.html

WaveShow_src.rar

Beginning to ~程 2006-03-16 11:00 发表评论
]]>
大小写{换的Ҏ【C/C++?/zhuanhttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4195.htmlBeginning to ~程Beginning to ~程Wed, 15 Mar 2006 05:31:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4195.htmlhttp://www.shnenglu.com/richardzeng/comments/4195.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4195.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/4195.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/4195.html
ASCII码表大家都很熟悉了吧Q利用码的排列规律,我们可以很容易的实现一些操作,比如判断是否是数字、大写转换{?/DIV>
q里写大写转换的函?
char toUpper(const char& ch)
{
    return ch & 0x5F;
}
char toLower(const char& ch)
{
    return ch | 0x20;
}
 
函数原理Q大写字母的差?2Q比如大写的A?5Q小写的A?7Q所以我们把双数第6位置0或?p实现大小写{换。{换成大写Ӟ把第6位置0Q用ch & 0x5F实现。{换成写时置1Q用ch | 0x20实现。怎么P相当的简单吧Q由此,我们可以写stringcȝtoUpper和toLower函数了。^_^Q更多技巧尽在探索中?/DIV>


]]>谈CMPP协议Q一Q?/zhuanhttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4186.htmlBeginning to ~程Beginning to ~程Wed, 15 Mar 2006 04:25:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4186.htmlhttp://www.shnenglu.com/richardzeng/comments/4186.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4186.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/4186.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/4186.html     CMPP协议的全U是中国Ud通信互联|短信网x口协议,它是联想亚信公司ҎSMMP协议Z国移动量w定做的Q是W合中国国情的一个短信协议,闲话不多说了Q说说CMPP的主要功能吧。(1Q短信发送(short message mobile originateQMOQ就是手机给SP发短信;Q?Q短信接受(short message mobile terminatedQMTQ这个就是SPl手机发的短信了Q通常我们手机上收到的不良短信是SPl我们的MT。CMPP协议的通信基础是TCP/IP为底层通信承蝲的,q接方式是长q接方式。SP与ISMG之间QSMSC和ISMG之间的交互过E中均采用异步方式,即Q一个网元在收到h消息后应立即回应?/FONT>
   下面看看它的消息定义QCMPP中的消息分ؓ消息头和消息体。消息头定义如下
 
 

字段?/SPAN>

字节?/SPAN>

cd

描述

Total_Length  

4

Unsigned Integer

消息总长?/SPAN>(含消息头及消息体)

Command_Id

4

Unsigned Integer

命o或响应类?/SPAN>

Sequence_Id

4

Unsigned Integer

消息水?/SPAN>,序累加,步长?/SPAN>1,循环使用Q一对请求和应答消息的流水号必须相同Q?/SPAN>

 
那么下面是SPq接到ISMG上了Q看它的Bindq接消息定义
 

字段?/SPAN>

字节?/SPAN>

属?/SPAN>

描述

Source_Addr 

6

Octet String

源地址Q此处ؓSP_IdQ即SP的企业代码?/SPAN>

AuthenticatorSource

16

Octet String

用于鉴别源地址。其值通过单向MD5 hash计算得出Q表C如下:

AuthenticatorSource =

MD5Q?/SPAN>Source_Addr+9 字节?/SPAN>0 +shared secret+timestampQ?/SPAN>

Shared secret ׃国移动与源地址实体事先商定Q?/SPAN>timestamp格式为:MMDDHHMMSSQ即月日时分U,10位?/SPAN>

Version

1

Unsigned Integer

双方协商的版本号(高位4bit表示ȝ本号,低位4bit表示ơ版本号)Q对?/SPAN>3.0的版本,?/SPAN>4bit?/SPAN>3Q低4位ؓ0

Timestamp

4

Unsigned Integer

旉戳的明文,由客L产生,格式?/SPAN>MMDDHHMMSSQ即月日时分U,10位数字的整型Q右寚w ?/SPAN>

 
Ҏ上的定义我们可以写出的代码,如下Q在VC环境下编写的

/*
 *函数功能Q徏立和CMPP|关的直接通\
 *输入条gQSP用户名const char *UserName,SP密码const char *PWD 
 */
void Ccmpp_API::CmppConnect(const char *UserName, const char *PWD)
{
 char netbuf[100];
 CMPP_CONNECT *bufer;
 bufer=(CMPP_CONNECT*)netbuf;
 memset(bufer, 0, 100);
 bufer->nTotalLength = htonl(39);//CMPP_CONNECT消息总长?BR> bufer->nCommandId = htonl(CMPP_CONNECT_tag);//消息标志
 //自动产生SeqId?BR>    if (sequenceid == 123456789i32)
 {
  sequenceid = 1;
 }else{
  sequenceid++;
 }
 bufer->nSeqId = htonl(sequenceid);
   
 int MD5Len;
 MD5_CTX md5;//MD5源字?BR> CTime TimeData = CTime::GetCurrentTime();
 CString timestamp = TimeData.Format("%m%d%H%M%S");
 unsigned char md5source[29];
 int Len1 = strlen(UserName);
 int Len2 = strlen(PWD); 
 MD5Len = Len1 + 9 +Len2 + timestamp.GetLength();
 memset(md5source, 0, MD5Len);
 
 memcpy(bufer->sSourceAddr, UserName, Len1);
 memcpy(md5source, UserName, Len1);
 
 for (int j = 0; j<Len2; j++)
 {
  md5source[j + Len1 + 9] = PWD[j];
 }
 for (int i=0;i<timestamp.GetLength();i++)
 {
  md5source[i + Len2 + Len1 + 9]=timestamp[i];
 }
 
 //q行md5加密转换
 md5.MD5Update(md5source, MD5Len);
 md5.MD5Final(md5source);
 memcpy(bufer->sAuthSource, md5source, 29);
 bufer->cVersion = 0x30;
 bufer->nTimeStamp = htonl(atoi(timestamp));
 CmppSocket.Send(bufer, 39, 0);//把消息打包发?BR> return;
}
 
今天到q,下次再写Q欢q交!


FeedBack:

# re: 谈CMPP协议Q一Q?/DIV>
2006-03-15 10:38 |
you say:
SP与ISMG之间QSMSC和ISMG之间的交互过E中均采用异步方式,即Q一个网元在收到h消息后应立即回应?

既然是异步方式,׃是收到请求后立即回应Q否则就是同步方式了

据我所知,CMPP采用的基于滑动窗口的异步方式Q默认情况下可以发最?6的CMPP package,而不必等待他们的resp.  回复
  


]]>Z么在VS2005重蝲输出q算W那么难 /zhuanhttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4179.htmlBeginning to ~程Beginning to ~程Wed, 15 Mar 2006 03:57:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4179.htmlhttp://www.shnenglu.com/richardzeng/comments/4179.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/15/4179.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/4179.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/4179.html阅读全文

]]>
VC中回调函C用的变n大法 /zhuanhttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4142.htmlBeginning to ~程Beginning to ~程Tue, 14 Mar 2006 09:33:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4142.htmlhttp://www.shnenglu.com/richardzeng/comments/4142.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4142.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/4142.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/4142.html
  1、在q里设:回调函数为A()(q是最单的情况Q不带参敎ͼ但我们应用的实际情况常常很会复杂)Q用回调函数的操作函数为B()Q?但B函数是需要参数的Q这个参数就是指向函数A的地址变量Q这个变量一般就是函数指针。用方法ؓQ?BR>
int A(char *p); // 回调函数
typedef int(*CallBack)(char *p) ; // 声明CallBack cd的函数指?
CallBack myCallBack ; // 声明函数指针变量
myCallBack = A; // 得到了函数A的地址

  B函数一般会写ؓ B(CallBack lpCall,char * P,........); // 此处省略了p后的参数形式 ?

  所以回调机制可解ؓQ函数B要完成一定功能,但他自己是无法实现全部功能的?需要借助于函数A来完成,也就是回调函数。B的实CؓQ?BR>
B(CallBack lpCall,char *pProvide)
{
 ........... // B 的自己实现功能语?BR> lpCall(PpProvide); // 借助回调完成的功?Q也是A函数来处理的?
 ........... // B 的自己实现功能语?BR>}
// -------------- 使用例子 -------------
char *p = "hello!";
CallBack myCallBack ;
myCallBack = A ;
B(A, p);

  以上是回调的基本应用,本文所说的变nQ其实是利用传入不同的函数地址Q实现调用者类与回调函数所在类的不同{换?BR>
  1、问题描q?BR>
  CUploadFile cd成数据上传,与相应的界面q度昄?BR>
  主要函数Send(...) 和回调函?GetCurState() ;

class CUploadFile : public CDialog
{
 ......
 int Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath) ;
 static int GetCurState(int nCurDone, int nInAll, void * pParam) ;
 ......
}
int CUploadFile ::Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath)
{
 ... // 导出传输数据的函?
 int ret = Upload( (LPSTR)(LPCTSTR)m_strData,
    GetCurState, // 在这个回调函C处理界面
    this, // CUploadFile 的自w指?Q也是pParam 所接受的参?
    (LPSTR)(LPCTSTR)UploadFilePath,
    "",
    "",
 );
}
int CUploadFile ::GetCurState(int nCurData, int nInAll, void * pParam)
{
 .........
 UploadFile *pThis = (UploadFile *)pParam; // nCurData 当前以传出的数据?
 // nInAll ȝ数据?BR> // 有了pThis可以对界面进行各U操作了?
 .............
}

  但大家仔l观察就可以发现Q这个类把数据传送和界面昄聚和C一P不容易得到复用。而且在复用过E中需要改动较多的地方 ?BR>
  请大家记住现在的回调函数传入的类本n的静态成员函数?

  现在我们把数据的传送和界面的显C分R回调则要传入的是界面处理类的静态函数?BR>
  界面处理c?CShowGUI,数据上传c?CUploadData

class CUploadData
{
 ......
 typedef int(*SetUploadCaller)(int nCurData, int nInAll, void * pParam);
 int UploadFile(LPCTSTR lpFileNamePath,LPVOID lparam,SetUploadCaller Caller );
 // 接受外界出入的参?主要是回调函数的地址通过参数Caller,
 int Send(LPCTSTR lpServerIP, LPCTSTR lpServerPort, LPCTSTR UploadFilePath) ;
 ...... // 注意此时不在需要GetCurState 函数??BR>}

class CShowGUI: public CDialog
{
 .......
 typedef int(*SetUploadCaller)(int nCurData, int nInAll, void * pParam);
 void SetCallBack(LPCTSTR strPath);
 static int GetCurState(int nCurData, int nInAll, void * pParam) ;
 CUploadData m_Uploa
 d ; // 数据上传cL界面昄cȝ一个成员变量?
 .......
}

void CShowGUI :: SetCallBack(LPCTSTR strPath)
{
 CUploadData myUploadData ;
 SetUploadCaller myCaller; // 声明一个函数指针变?
 myCaller = CurState ; // 取得界面处理函数的地址
 myUploadData .UploadFile(strPath,this,myCaller); // 界面处理cȝ函数传入,实现了数据传入与界面处理的分?.
}

  通过上面的演C做C界面与数据的分离,回调函数分别扮演了不同角?所以随着处理问题的不同应灉|应用Q但同样因ؓ处理数据cM知道界面处理cL外部调用cȝcdQ而更无法灉|地处理界面的不同昄方式。这斚wq希望喜Ƣ钻研技术的朋友l箋研究?A >陈刚

]]>
C++指针探讨 (? 函数指针 /zhuanhttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4137.htmlBeginning to ~程Beginning to ~程Tue, 14 Mar 2006 08:44:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4137.htmlhttp://www.shnenglu.com/richardzeng/comments/4137.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4137.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/4137.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/4137.html  我们先简单的说一下函数指针。(q一部䆾没什么h|U是Z引出下一节的内容Q?BR>   
 2 常规函数指针

        void(*fp)();

  fp 是一个典型的函数指针Q用于指向无参数Q无q回值的函数?/P>

        void(*fp2)(int);

  fp2 也是一个函数指针,用于指向有一个整型参敎ͼ无返回值的函数?BR>  当然Q有l验人士一般都会徏议用typedef来定义函数指针的cdQ如Q?/P>

        typedef void(* FP)();
        FP fp3; 
// 和上面的fp一L定义?/SPAN>

  函数指针之所以让初学者畏惧,最主要的原因是它的括号太多了;某些用途的函数指针Q往往会让人陷在括号堆中出不来Q这里就不D例了Q因Z是本文讨论的范围Qtypedef Ҏ可以有效的减括L数量Q以及理清层ơ,所以受到推荐。本文暂时只考虑单的函数指针Q因此暂不用到typedef?BR>
  假如有如下两个函敎ͼ

  void f1()
  
{
      std::cout 
<< "call f " << std::endl;
  }

  
  
void f2(int a)
  
{
      std::cout 
<< "call f2( " << a << " )" << std::endl;
  }

  现在需要通过函数指针来调用,我们需要给指针指定函数Q?/P>

  fp = &f1; // 也可以用Qfp = f1;
  fp2= &f2; // 也可以用Qfp2= f2;
  void (*fp3)() = &f1; // 也可以用Qvoid (*fp3)() = f1;  
  
//调用时如下:
  fp(); // ?nbsp;(*fp)();
  fp2(1); // ?nbsp;(*fp2)(1);
  fp3();  // ?nbsp;(*fp3)();

  对于此两U调用方法,效果完全一P我推荐用前一U。后一U不仅仅是多打了键盘Q而且也损׃一些灵zL。这里暂且不说它?BR>  
  C++cd安全。也是_不同cd的变量是不能直接赋值的Q否则轻则警告,重则报错。这是一个很有用的特性,常常能帮我们扑ֈ问题。因此,有识之士认ؓQC++中的M一外警告都不能忽视。甚x人提出,~译的时候不能出CQ何警告信息,也就是说Q警告应该当作错误一样处理?BR>  
  比如Q我们把f1赋值给fp2Q那么C++~译?vc7.1)׃报错Q?/P>

  fp2 = &f1; // error C2440: ??nbsp;: 无法从“void (__cdecl *)(void)”{换ؓ“void (__cdecl *)(int)?/SPAN>
  fp1 = &f1; // OK

  q样Q编译器可以帮我们找出编码上的错误,节省了我们的排错旉?BR>  
  考虑一下C++标准模板库的sort函数Q?/P>

  // 快速排序函?/SPAN>
  template<typename RandomAccessIterator, typename BinaryPredicate>
     
void sort(
        RandomAccessIterator _First, 
// 需排序数据的第一个元素位|?/SPAN>
        RandomAccessIterator _Last,  // 需排序数据的最后一个元素位|(不参与排序)
        BinaryPredicate _Comp     // 排序使用的比较算?可以是函数指针、函数对象等)
     );

  比如Q我们有一个整型数l:

  int n[5= {3,2,1,8,9};

  要对它进行升序排序,我们需定义一个比较函敎ͼ

  bool less(int a, int b)
  
{
      
return a < b; 
  }

  然后用:

  sort(n, n+5, less);

  要是惛_它进行降序排序,我们只要换一个比较函数就可以了。C/C++的标准模板已l提供了less和great函数Q因此我们可以直接用下面的语句来比较Q?nbsp; 

  sort(n, n+5, great);


  q样Q不需要改变sort函数的定义,可以按LҎq行排序Q是不是很灵z?  
  q种用法以C++的标准模板库(STL)中非常流行。另外,操作pȝ中也l常使用回调(CallBack)函数Q实际上Q所谓回调函敎ͼ本质是函数指针?/P>

  看v来很单吧Q这是最普通的C语言指针的用法。本来这是一个很妙的事情,但是当C++来Ӟ世界开始变了样?BR>  假如Q用来进行sort的比较函数是某个cȝ成员Q那又如何呢Q?BR>



]]>
C++指针探讨 (? 成员函数指针 /zhuanhttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4135.htmlBeginning to ~程Beginning to ~程Tue, 14 Mar 2006 08:42:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4135.htmlhttp://www.shnenglu.com/richardzeng/comments/4135.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/14/4135.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/4135.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/4135.html  然而C++的指针却常常l我一U束手束脚的感觉。C++比C语言有更严格的静态类型,更加cd安全Q强调编译时查。因此,对于C语言中最Ҏ错用的指针,更是不能放过QC++的指针被分成数据指针Q数据成员指针,函数指针Q成员函数指针,而且不能随便怺转换。而且q些指针的声明格式都不一P

数据指针 T *
成员数据指针 T::*
函数指针 R (*)(...)
成员函数指针 R (T::*)(...)

  管C++中仍然有万能指针void*Q但它却属于被批斗的对象Q而且再也不能“万能”了。它不能转换成成员指针?/P>

  q样一来,C++的指针就变得很尴:我们需要一U指针能够指向同一cd的数据,不管q个数据是普通数据,q是成员数据Q我们更需要一U指针能够指向同一cd的函敎ͼ不管q个函数是静态函敎ͼq是成员函数。但是没有,臛_从现在的C++标准中,q没有看到?BR> 
沐枫|志 C++指针探讨(?成员函数指针

  自从有了c,我们开始按照 数据Q操作 的方式来l织数据l构Q自从有了模板,我们又开始把 数据 ?法 分离Q以侉K用,实在够折腾h的。但不管怎么折腾Q现在大多数函数都不再单w,都嫁l了c,q了围城。可是我们仍焉要能够自p用这些成员函数?BR>  考虑一下windows下的定时调用。SetTimer函数的原型是q样的:

UINT_PTR SetTimer(
    HWND hWnd,
    UINT_PTR nIDEvent,
    UINT uElapse,
    TIMERPROC lpTimerFunc
);
  其中Q参数就不解释了Q这个函C计大多数windows开发h员都知道。lpTimerFunc是个会被定时调用的函数指针。假如我们不通过WM_TIMER消息来触发定时器Q而是通过lpTimerFunc来定时工作,那么我们只能用普通函数或静态函敎ͼ而无论如何都不能使用成员函数Q哪怕通过静态函数{调也不行?BR>
  再考虑一下线E的创徏Q?BR>
uintptr_t _beginthread( 
   
void*start_address )( void * ),
   unsigned stack_size,
   
void *arglist 
);
  start_address仍然只支持普通函数。不q这回好了,它允许回调函C个void*参数Q它会arglist作ؓ参数来调用start_address。于是,聪明的C++E序员,利用arglist传递this指针Q从而利用静态函数成功的调用C成员函数了:
class mythread
{
  
public:
    
static void doit(void* pThis)
    
{
    ((mythread*)pThis)
->doit();
    }

    
void doit(){}
}
;

main()
{
  
  mythread
* pmt = new mythread;
  _beginthread(
&mythread::doit, 0, (void*)pmt);
  
}

  但是昄QC++E序员肯定不会因此而满뀂这里头有许多被C++批判的不安定因素。它使用了C++中被认ؓ不安全的cd转换Q不安全的void*指针Q等{等{。但q是pȝ为C语言留下的调用接口,q也p了。那么假如,我们在C++E序中如何来调用成员函数指针呢?
  如下例,我们打算对vector中的所有类调用其指定的成员函数Q?/P>

#include <vector>
#include 
<algorithm>
#include 
<functional>
#include 
<iostream>
using namespace std;

class A
{
    
int value;
public:
    A(
int v){value = v;}
    
void doit(){ cout << value << endl;};
    
static void call_doit(A& rThis)
    
{
        rThis.doit();
    }

}
;


int main()
{
    vector
<A> va;
    va.push_back(A(
1));
    va.push_back(A(
2));
    va.push_back(A(
3));
    va.push_back(A(
4));
    
//Ҏ1:
    
//for_each(va.begin(), va.end(), &A::doit); //error
    
//Ҏ2:
    for_each(va.begin(), va.end(), &A::call_doit);
    
//Ҏ3:
    for_each(va.begin(), va.end(), mem_fun_ref<void, A>(&A::doit));

    system(
"Pause");

    
return 0;
}

  Ҏ1Q编译不能通过。for_each只允许具有一个参数的函数指针或函数对象,哪怕A::doit默认有一个this指针参数也不行。不是for_each没考虑到这一点,而是Ҏ做不刎ͼ
  Ҏ2Q显然是受到了beginthread的启发,使用一个静态函数来转调用,哈哈成功了。但是不爽!q不是C++?BR>  Ҏ3Q呼Q好不容易啊Q终于用mem_fun_ref包装成功了成员函数指针?BR>  gҎ3不错Q又是类型安全的Q又可以通用Q-慢着Q首先,它很丑,哪有调用普通C函数指针那么漂亮啊(见方?Q,用了一大串包装Q又是尖括号又是圆括Pq少不了&P其次Q它只能包装不超q一个参数的函数Q尽它在for_each中够用了Q但是你要是想用在超q一个参数的场合Q那只有一句话Q不可能的Q务?BR>

  是的Q在标准C++中,q是不可能的d。但事情q不L悲观的,臛_有许多第三方库提供了越mem_fun的包装。如boost::function{等。但是它也有限制Q它所支持的参C然是有限的,只有十多个,管够你用的了;同样Q它也是丑陋的,永远不要惛_能够单的?amp;来搞定?BR>
  也许Q以失去丽的代P来换取质量上的保证,q也是C++对于函数指针的一U无奈吧…?BR>
  期待C++0x版本。它通过可变模板参数Q能够让mem_fun的参数达到无限个…?BR>
Q-Q-Q-Q-
   BTW: C++Builder扩展了一个关键字 closure Q允许成员函数指针如同普通函数指针一样用。也许C++0x能考虑一下…?/P>

]]>
ACM学习|站 http://www.shnenglu.com/richardzeng/archive/2006/03/10/3959.htmlBeginning to ~程Beginning to ~程Fri, 10 Mar 2006 03:01:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/10/3959.htmlhttp://www.shnenglu.com/richardzeng/comments/3959.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/10/3959.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/3959.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/3959.html 
同济大学?Online Judge - http://acm.tongji.edu.cn/
江大学?Online Judge - http://acm.zju.edu.cn/
北京大学?Online Judge - http://acm.pku.edu.cn/
吉林大学?Online Judge - http://acm.jlu.edu.cn/
四川大学?Online Judge - http://cs.scu.edu.cn/acm
汕头大学?Online Judge - http://acm.stu.edu.cn/
中科大的 Online Judge - http://acm.ustc.edu.cn/index.php
哈工大的 Online Judge - http://acm.hit.edu.cn/acm.php
西班牙的 Universidad de Valladolid - http://acm.uva.es/
俄罗斯乌拉尔大学 - http://acm.timus.ru/

]]>
l构化设计的救命E草Q回调机? / ?Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=253623http://www.shnenglu.com/richardzeng/archive/2006/03/09/3929.htmlBeginning to ~程Beginning to ~程Thu, 09 Mar 2006 03:27:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/09/3929.htmlhttp://www.shnenglu.com/richardzeng/comments/3929.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/09/3929.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/3929.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/3929.html摘要Q开发模式的立是Y件开发过E中不可~少的一部分Q就目前来说Q面向过E和面向对象是两U主要的设计ҎQ虽焉向对象OOP是比较流行的字眼Q但不表C面向过E就一定好无作为,毕竟面向q程设计Ҏ也有适合其应用的软gpȝQ以功能操作ZQ扩展性要求不高,无需q多考虑复用以及软g的通用性能。那是不是面向过E的设计Ҏ对于诸如pȝ框架扩展问题׃毫没有办法了呢?

按照面向q程的基本原则,划分pȝ功能模块、模块细分到函数、生成系l整体的l构模型Q似乎在整个q程中没有Q何东西可以用来提供系l扩展,其实解决的方法还是有的,q根救命E草是回调机制?/P>

一谈到回调机制Q当然就不了我们的主角Q系lAPI(通常都是)和回调函敎ͼq两者缺一不可。其实回调的基本思想是ql给我们提供一些接口,也就是常使用的APIQ这U函数可以将某个其他函数的地址作ؓ其参C一Q而且可以利用该地址对这个函数进行调用,而被调用的函数就是我们通常所说的回调函数了?BR>下面l个回调函数使用的小例子Q?BR>Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
//相当于我们提到的pȝAPI
mainFunc( void*  userFunc )//当然参数不会q么单,只是模拟
{
 while (...)
 {
  printf("ok!");
                //调用回调函数?BR>  if (userFunc!=NULL) 
   userFunc();
 }
}
可以看出MainFunc可以Ҏ函数userFunc的地址调用它?BR>Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
q样使用者只需要定义一个函敎ͼvoid myFunc()Q然后按照mainFunc(&myFunc)(&只表CZ递的是函数的地址Q无具体含义)Q就可以让我们的mainFunc来调用myFunc从而实现相应的功能Q这样当然可以完成我们预期的目的Q扩展现有系l?/P>

在windowspȝ中,支持q种回调机制的系lAPI不占数Q像实现ListControl排序的SortItem()函数Q还有操作Font使用的函数EnumFontFamilies()都有提供q种回调机制Q得我们的用户有机会添加自己期望的功能实现。当Ӟ使用回调函数q不是一个轻杄事情Q如果我们的pȝ中存在了大量的回调函数是很难理的,q个׃pȝ中存在大量全局变量一P出现多个函数争相讉K同一个变量我们就很难使用单的逻辑来处理,Ҏ陷入混ؕQ因此,管回调机制可以在某U程度上辑ֈ我们的目的,但切不可乱加使用Q不然后果很N料?/P>

当然至于详细的回调函数实玎ͼq需要大家潜心研IӞq里我只是ȝ一下:
1 回调函数是由开发者按照一定的原型q行定义的函?每个回调函数都必遵循这个原型来设计)

例如Q?BR>Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
BOOL CALLBACK DialogProc(
    
     HWND hwndDlg, // handle of dialog box
     UINT uMsg, // message
     WPARAM wParam, // first message parameter
     LPARAM lParam // second message parameter
     );
Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
说明Q?BR>回调函数必须有关键词 CALLBACK
回调函数本n必须是全局函数或者静态函敎ͼ不可定义为某个特定的cȝ成员函数

2 回调函数q不由开发者直接调用执?只是使用pȝ接口API函数作ؓL)
3 回调函数通常作ؓ参数传递给pȝAPIQ由该API来调?BR>4 回调函数可能被系lAPI调用一ơ,也可能被循环调用多次(SortItem是自调?

最后说句题外话Q其实windowspȝ中还有另一U机Ӟ消息机制Q也是一个比较不错的工具Q能够ؓ很多实际的问题提供解x法,q个以后再ȝ了?/P>

]]>
五大内存分区 /http://blog.csdn.net/welcome_ck/archive/2004/12/24/227961.aspxhttp://www.shnenglu.com/richardzeng/archive/2006/03/09/3928.htmlBeginning to ~程Beginning to ~程Thu, 09 Mar 2006 03:20:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/09/3928.htmlhttp://www.shnenglu.com/richardzeng/comments/3928.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/09/3928.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/3928.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/3928.html
    在C++中,内存分成5个区Q他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区?BR>    栈,是那些q译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等?BR>    堆,是那些由new分配的内存块Q他们的释放~译器不ȝQ由我们的应用程序去控制Q一般一个newp对应一个delete。如果程序员没有释放掉,那么在程序结束后Q操作系l会自动回收?BR>    自由存储区,是那些由malloc{分配的内存块,他和堆是十分怼的,不过它是用free来结束自q生命的?BR>    全局/静态存储区Q全局变量和静态变量被分配到同一块内存中Q在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有q个区分了,他们共同占用同一块内存区?BR>    帔R存储区,q是一块比较特D的存储区,他们里面存放的是帔RQ不允许修改Q当Ӟ你要通过非正当手D也可以修改Q而且Ҏ很多Q?BR>明确区分堆与?BR>    在bbs上,堆与栈的区分问题Q似乎是一个永恒的话题Q由此可见,初学者对此往往是؜淆不清的Q所以我军_拿他W一个开刀?BR>    首先Q我们D一个例子:
    void f() { int* p=new int[5]; }
    q条短短的一句话包含了堆与栈,看到newQ我们首先就应该惛_Q我们分配了一块堆内存Q那么指针p呢?他分配的是一块栈内存Q所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在E序会先定在堆中分配内存的大小Q然后调用operator new分配内存Q然后返回这块内存的首地址Q放入栈中,他在VC6下的汇编代码如下Q?BR>    00401028   push        14h
    0040102A   call        operator new (00401060)
    0040102F   add         esp,4
    00401032   mov         dword ptr [ebp-8],eax
    00401035   mov         eax,dword ptr [ebp-8]
    00401038   mov         dword ptr [ebp-4],eax
    q里Q我们ؓ了简单ƈ没有释放内存Q那么该怎么去释攑֑Q是delete p么?澻I错了Q应该是delete []pQ这是ؓ了告诉编译器Q我删除的是一个数l,VC6׃Ҏ相应的Cookie信息去进行释攑ֆ存的工作?BR>    好了Q我们回到我们的主题Q堆和栈I竟有什么区别?
    主要的区别由以下几点Q?BR>    1、管理方式不同;
    2、空间大不同;
    3、能否生碎片不同;
    4、生长方向不同;
    5、分配方式不同;
    6、分配效率不同;
    理方式Q对于栈来讲Q是q译器自动理Q无需我们手工控制Q对于堆来说Q释攑ַ作由E序员控ӞҎ产生memory leak?BR>    I间大小Q一般来讲在32位系l下Q堆内存可以辑ֈ4G的空_从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲Q一般都是有一定的I间大小的,例如Q在VC6下面Q默认的栈空间大是1MQ好像是Q记不清楚了Q。当Ӟ我们可以修改Q?nbsp;  
    打开工程Q依ơ操作菜单如下:Project->Setting->LinkQ在Category 中选中OutputQ然后在Reserve中设定堆栈的最大值和commit?BR>注意Qreserve最gؓ4ByteQcommit是保留在虚拟内存的页文g里面Q它讄的较大会使栈开辟较大的|可能增加内存的开销和启动时间?BR>    片问题Q对于堆来讲Q频J的new/delete势必会造成内存I间的不q箋Q从而造成大量的碎片,使程序效率降低。对于栈来讲Q则不会存在q个问题Q因为栈是先q后出的队列Q他们是如此的一一对应Q以至于永远都不可能有一个内存块从栈中间弹出Q在他弹Z前,在他上面的后q的栈内容已l被弹出Q详l的可以参考数据结构,q里我们׃再一一讨论了?BR>    生长方向Q对于堆来讲Q生长方向是向上的,也就是向着内存地址增加的方向;对于栈来Ԍ它的生长方向是向下的Q是向着内存地址减小的方向增ѝ?BR>    分配方式Q堆都是动态分配的Q没有静态分配的堆。栈?U分配方式:静态分配和动态分配。静态分配是~译器完成的Q比如局部变量的分配。动态分配由alloca函数q行分配Q但是栈的动态分配和堆是不同的,他的动态分配是q译器q行释放Q无需我们手工实现?BR>    分配效率Q栈是机器系l提供的数据l构Q计机会在底层Ҏ提供支持Q分配专门的寄存器存放栈的地址Q压栈出栈都有专门的指o执行Q这决定了栈的效率比较高。堆则是C/C++函数库提供的Q它的机制是很复杂的Q例如ؓ了分配一块内存,库函C按照一定的法Q具体的法可以参考数据结?操作pȝQ在堆内存中搜烦可用的够大的I间Q如果没有够大的I间Q可能是׃内存片太多Q,有可能调用pȝ功能d加程序数据段的内存空_q样有Z分到_大小的内存,然后q行q回。显Ӟ堆的效率比栈要低得多?BR>    从这里我们可以看刎ͼ堆和栈相比,׃大量new/delete的用,Ҏ造成大量的内存碎片;׃没有专门的系l支持,效率很低Q由于可能引发用h和核心态的切换Q内存的甌Q代价变得更加昂c所以栈在程序中是应用最q泛的,q是函数的调用也利用栈d成,函数调用q程中的参数Q返回地址QEBP和局部变量都采用栈的方式存放。所以,我们推荐大家量用栈Q而不是用堆?BR>    虽然栈有如此众多的好处,但是׃和堆相比不是那么灉|Q有时候分配大量的内存I间Q还是用堆好一些?BR>    无论是堆q是栈,都要防止界现象的发生(除非你是故意使其界Q,因ؓ界的结果要么是E序崩溃Q要么是摧毁E序的堆、栈l构Q生以想不到的l果,q是在你的E序q行q程中,没有发生上面的问题,你还是要心Q说不定什么时候就崩掉Q那时候debug可是相当困难的:Q?BR>    对了Q还有一件事Q如果有人把堆栈合v来说Q那它的意思是栈,可不是堆Q呵呵,清楚了?
static用来控制变量的存储方式和可见?BR>       函数内部定义的变量,在程序执行到它的定义处时Q编译器为它在栈上分配空_函数在栈上分配的I间在此函数执行l束时会释放掉,q样׃生了一个问? 如果惛_函数中此变量的g存至下一ơ调用时Q如何实玎ͼ 最Ҏ惛_的方法是定义一个全局的变量,但定义ؓ一个全局变量有许多缺点,最明显的缺Ҏ破坏了此变量的访问范_使得在此函数中定义的变量Q不仅仅受此函数控制Q?/P>

       需要一个数据对象ؓ整个c而非某个对象服务,同时又力求不破坏cȝ装?卌求此成员隐藏在类的内部,对外不可见?/P>

       static的内部机Ӟ
       静态数据成员要在程序一开始运行时必d在。因为函数在E序q行中被调用Q所以静态数据成员不能在M函数内分配空间和初始化?BR>       q样Q它的空间分配有三个可能的地方,一是作为类的外部接口的头文Ӟ那里有类声明Q二是类定义的内部实玎ͼ那里有类的成员函数定义;三是应用E序的mainQ)函数前的全局数据声明和定义处?BR>      静态数据成员要实际地分配空_故不能在cȝ声明中定义(只能声明数据成员Q。类声明只声明一个类的“尺寸和规格”,q不q行实际的内存分配,所以在cd明中写成定义是错误的。它也不能在头文件中cd明的外部定义Q因为那会造成在多个用该cȝ源文件中Q对光复定义?BR>      static被引入以告知~译器,变量存储在E序的静态存储区而非栈上I间Q静?BR>数据成员按定义出现的先后序依次初始化,注意静态成员嵌套时Q要保证所嵌套的成员已l初始化了。消除时的顺序是初始化的反顺序?/P>

       static的优势:
       可以节省内存Q因为它是所有对象所公有的,因此Q对多个对象来说Q静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一P但它的值是可以更新的。只要对静态数据成员的值更Cơ,保证所有对象存取更新后的相同的|q样可以提高旉效率?/P>

        引用静态数据成员时Q采用如下格式:
         <cd>::<静态成员名>
    如果静态数据成员的讉K权限允许的话(即public的成?Q可在程序中Q按上述格式
来引用静态数据成员?/P>

       PS:
      (1)cȝ静态成员函数是属于整个c而非cȝ对象Q所以它没有this指针Q这导?BR>了它仅能讉Kcȝ静态数据和静态成员函数?BR>      (2)不能静态成员函数定义ؓ虚函数?BR>      (3)׃静态成员声明于cMQ操作于其外Q所以对其取地址操作Q就多少有些Ҏ
Q变量地址是指向其数据cd的指?Q函数地址cd是一个“nonmember函数指针”?/P>

      (4)׃静态成员函数没有this指针Q所以就差不多等同于nonmember函数Q结果就
产生了一个意想不到的好处Q成Z个callback函数Q得我们得以将C++和C-based X W
indowpȝl合Q同时也成功的应用于U程函数w上?BR>      (5)staticq没有增加程序的时空开销Q相反她q羃短了子类对父c静态成员的讉K
旉Q节省了子类的内存空间?BR>      (6)静态数据成员在<定义或说?gt;时前面加关键字static?BR>      (7)静态数据成员是静态存储的Q所以必d它进行初始化?BR>      (8)静态成员初始化与一般数据成员初始化不同:
      初始化在cM外进行,而前面不加staticQ以免与一般静态变量或对象相؜淆;
      初始化时不加该成员的讉K权限控制WprivateQpublic{;
           初始化时使用作用域运符来标明它所属类Q?BR>           所以我们得出静态数据成员初始化的格式:
         <数据cd><cd>::<静态数据成员名>=<?gt;
      (9)Z防止父类的媄响,可以在子cd义一个与父类相同的静态变量,以屏蔽父cȝ影响。这里有一炚w要注意:我们说静态成员ؓ父类和子cd享,但我们有重复定义了静态成员,q会不会引v错误呢?不会Q我们的~译器采用了一U绝妙的手法Qname-mangling 用以生成唯一的标志?BR>



]]>
关于C++中构造函数的说明 /转孙鑫VC++http://www.shnenglu.com/richardzeng/archive/2006/03/09/3925.htmlBeginning to ~程Beginning to ~程Thu, 09 Mar 2006 02:59:00 GMThttp://www.shnenglu.com/richardzeng/archive/2006/03/09/3925.htmlhttp://www.shnenglu.com/richardzeng/comments/3925.htmlhttp://www.shnenglu.com/richardzeng/archive/2006/03/09/3925.html#Feedback0http://www.shnenglu.com/richardzeng/comments/commentRss/3925.htmlhttp://www.shnenglu.com/richardzeng/services/trackbacks/3925.html在国内的C++图书中,关于构造函数的说明Q要么是错误的,要么没有真正说清楚构造函数的作用Q因此在我的视频中,Ҏ造函数的讲解Q也有一部分错误的叙q。对于C++构造函C些错误认识的传播Q我也相当于起了推L助澜的作用,在此反省一下,q给出正的叙述?/P>

Q感谢西安Y件园的王先生为我指出错误Q感谢网友backer帮助我找出正的{案。)

在光盘VC02中,在介l构造函数时Q我_“构造函数最重要的作用是创徏对象本nQ对象内存的分配由构造函数来完成的”,q句话是错的Q对象内存的分配和构造函数没有关p,对象内存的分配是q译器来完成的Q构造函数的作用是对对象本n做初始化工作Q也是l用h供初始化cM成员变量的一U方式,在类对象有虚表的情况下,构造函数还对虚表进行初始化?/P>

另外Q我_“C++又规定,如果一个类没有提供M的构造函敎ͼ则C++提供一个默认的构造函敎ͼ由C++~译器提供)”,q句话也是错误的Q正的是:

如果一个类中没有定义Q何的构造函敎ͼ那么~译器只有在以下三种情况Q才会提供默认的构造函敎ͼ
1、如果类有虚拟成员函数或者虚拟承父c(x虚拟基类Q时Q?BR>2、如果类的基cL构造函敎ͼ可以是用户定义的构造函敎ͼ或编译器提供的默认构造函敎ͼQ?BR>3、在cM的所有非静态的对象数据成员Q它们对应的cM有构造函敎ͼ可以是用户定义的构造函敎ͼ或编译器提供的默认构造函敎ͼ?/P>

]]>
C++的多态性实现机制剖?/转孙?/title><link>http://www.shnenglu.com/richardzeng/archive/2006/03/09/3924.html</link><dc:creator>Beginning to ~程</dc:creator><author>Beginning to ~程</author><pubDate>Thu, 09 Mar 2006 02:56:00 GMT</pubDate><guid>http://www.shnenglu.com/richardzeng/archive/2006/03/09/3924.html</guid><wfw:comment>http://www.shnenglu.com/richardzeng/comments/3924.html</wfw:comment><comments>http://www.shnenglu.com/richardzeng/archive/2006/03/09/3924.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/richardzeng/comments/commentRss/3924.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/richardzeng/services/trackbacks/3924.html</trackback:ping><description><![CDATA[<BR> <P align=center>  <P> <P align=center>――即VC++视频W三课this指针详细说明<BR> <P> <P> <P align=center>作者:孙鑫 旉Q??xml:namespace prefix = st1 /><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="12" Month="1" Year="2006">2006q??2?/st1:chsdate>星期?BR> <P> <P> <P>要更好地理解C++的多态性,我们需要弄清楚函数覆盖的调用机Ӟ因此Q首先我们介l一下函数的覆盖?/P> <H1>1.   函数的覆?/H1> <P>我们先看一个例子:</P> <DIV> <P align=center><FONT size=2>?FONT face=Arial>1- 1</FONT></FONT></P></DIV> <P>#include <iostream.h></P> <P>class animal</P> <P>{</P> <P>public:</P> <P>       void sleep()</P> <P>       {</P> <P>              cout<<"animal sleep"<<endl;</P> <P>       }</P> <P>       <B>void breathe()<BR> <P></B> <P> <P><B>       {<BR> <P></B> <P> <P><B>              cout<<"animal breathe"<<endl;<BR> <P></B> <P> <P><B>       }<BR> <P></B> <P> <P>};</P> <P>class fish:public animal</P> <P>{</P> <P>public:</P> <P>       <B>void breathe()<BR> <P></B> <P> <P><B>       {<BR> <P></B> <P> <P><B>              cout<<"fish bubble"<<endl;<BR> <P></B> <P> <P><B>       }<BR> <P></B> <P> <P>};</P> <P>void main()</P> <P>{</P> <P>       <B>fish fh;<BR> <P></B> <P> <P>       <B>animal *pAn=&fh;<BR> <P></B> <P> <P><B>       pAn->breathe();<BR> <P></B> <P> <DIV> <P>}</P></DIV> <P>       注意Q在?-1的程序中没有定义虚函数。考虑一下例1-1的程序执行的l果是什么?</P> <P>       {案是输出:animal breathe</P> <P>       在类fish中重写了breathe()函数Q我们可以称为函数的覆盖。在main()函数中首先定义了一个fish对象fhQ接着定义了一个指向animal的指针变量pAnQ将fh的地址赋给了指针变量pAnQ然后利用该变量调用pAn->breathe()。许多学员往往这U情况和C++的多态性搞hQ认为fh实际上是fishcȝ对象Q应该是调用fishcȝbreathe()Q输出“fish bubble”,然后l果却不是这栗下面我们从两个斚w来讲q原因?/P> <P>1?nbsp; ~译的角?/P> <P>C++~译器在~译的时候,要确定每个对象调用的函数的地址Q这UCؓ早期l定Qearly bindingQ,当我们将fishcȝ对象fh的地址赋给pAnӞC++~译器进行了cd转换Q此时C++~译器认为变量pAn保存是animal对象的地址。当在main()函数中执行pAn->breathe()Ӟ调用的当然就是animal对象的breathe函数?/P> <P>2?nbsp; 内存模型的角?/P> <P>我们l出了fish对象内存模型Q如下图所C:</P> <P align=center></P> <P> <P><?xml:namespace prefix = v /><v:rect><FONT face="Times New Roman" size=3><IMG onmousewheel="return bbimg(this)" style="WIDTH: 401px; CURSOR: pointer; ZOOM: 80%; HEIGHT: 213px" onclick=javascript:window.open(this.src); height=188 src="http://www.mybole.com.cn/bbs/UploadFile/2006-1/200611213332815.gif" width=359 onload="javascript:if(this.width>screen.width-500)this.style.width=screen.width-500;" border=0></FONT></v:rect></P> <P> <P> <P> <P> <P> <P><BR><BR><BR><BR><BR> <P><BR clear=all></P> <P align=center>?- 1 fishcd象的内存模型</P> <P> <P><FONT face="Times New Roman" size=3></FONT></P> <P><FONT size=3> <P>我们构?FONT face="Times New Roman">fish</FONT>cȝ对象Ӟ首先要调?FONT face="Times New Roman">animal</FONT>cȝ构造函数去构?FONT face="Times New Roman">animal</FONT>cȝ对象Q然后才调用<FONT face="Times New Roman">fish</FONT>cȝ构造函数完成自w部分的构造,从而拼接出一个完整的<FONT face="Times New Roman">fish</FONT>对象。当我们?FONT face="Times New Roman">fish</FONT>cȝ对象转换?FONT face="Times New Roman">animal</FONT>cdӞ该对象就被认为是原对象整个内存模型的上半部分Q也是?FONT face="Times New Roman">1-1</FONT>中的?FONT face="Times New Roman">animal</FONT>的对象所占内存”。那么当我们利用cd转换后的对象指针去调用它的方法时Q当然也是调用它所在的内存中的Ҏ。因此,出现?FONT face="Times New Roman">2.13</FONT>所C的l果Q也顺理成章了?/P> <H1><FONT face="Times New Roman">2.<FONT size=6>   </FONT></FONT>多态性和虚函?/H1> <P>正如很多学员所惻I在例<FONT face="Times New Roman">1-1</FONT>的程序中Q我们知?FONT face="Times New Roman">pAn</FONT>实际指向的是<FONT face="Times New Roman">fish</FONT>cȝ对象Q我们希望输出的l果是鱼的呼吸方法,卌?FONT face="Times New Roman">fish</FONT>cȝ<FONT face="Times New Roman">breathe</FONT>Ҏ。这个时候,p轮到虚函数登Z?/P> <P>前面输出的结果是因ؓ~译器在~译的时候,已l确定了对象调用的函数的地址Q要解决q个问题p使用q绑定(<FONT face="Times New Roman">late binding</FONT>Q技术。当~译器用迟l定Ӟ׃在运行时再去定对象的类型以及正的调用函数。而要让编译器采用q绑定,p在基cM声明函数时?FONT face="Times New Roman">virtual</FONT>关键字(注意Q这是必ȝQ很多学员就是因为没有用虚函数而写出很多错误的例子Q,q样的函数我们称函数。一旦某个函数在基类中声明ؓ<FONT face="Times New Roman">virtual</FONT>Q那么在所有的zcM该函数都?FONT face="Times New Roman">virtual</FONT>Q而不需要再昄的声明ؓ<FONT face="Times New Roman">virtual</FONT>?/P> <P>下面修改?FONT face="Times New Roman">1-1</FONT>的代码,?FONT face="Times New Roman">animal</FONT>cM?FONT face="Times New Roman">breathe()</FONT>函数声明?FONT face="Times New Roman">virtual</FONT>Q如下:</P> <DIV> <P align=center><FONT size=2>?FONT face=Arial>1- 2</FONT></FONT></P></DIV> <P><FONT face="Times New Roman">#include <iostream.h></FONT></P> <P><FONT face="Times New Roman">class animal</FONT></P> <P><FONT face="Times New Roman">{</FONT></P> <P><FONT face="Times New Roman">public:</FONT></P> <P><FONT face="Times New Roman">       void sleep()</FONT></P> <P><FONT face="Times New Roman">       {</FONT></P> <P><FONT face="Times New Roman">              cout<<"animal sleep"<<endl;</FONT></P> <P><FONT face="Times New Roman">       }</FONT></P> <P><FONT face="Times New Roman">       <B>virtual </B>void breathe()</FONT></P> <P><FONT face="Times New Roman">       {</FONT></P> <P><FONT face="Times New Roman">              cout<<"animal breathe"<<endl;</FONT></P> <P><FONT face="Times New Roman">       }</FONT></P> <P><FONT face="Times New Roman">};</FONT></P> <P><FONT face="Times New Roman">class fish:public animal</FONT></P> <P><FONT face="Times New Roman">{</FONT></P> <P><FONT face="Times New Roman">public:</FONT></P> <P><FONT face="Times New Roman">       void breathe()</FONT></P> <P><FONT face="Times New Roman">       {</FONT></P> <P><FONT face="Times New Roman">              cout<<"fish bubble"<<endl;</FONT></P> <P><FONT face="Times New Roman">       }</FONT></P> <P><FONT face="Times New Roman">};</FONT></P> <P><FONT face="Times New Roman">void main()</FONT></P> <P><FONT face="Times New Roman">{</FONT></P> <P><FONT face="Times New Roman">       fish fh;</FONT></P> <P><FONT face="Times New Roman">       animal *pAn=&fh;</FONT></P> <P><FONT face="Times New Roman">       pAn->breathe();</FONT></P> <DIV> <P><FONT face="Times New Roman">}</FONT></P></DIV> <P>大家可以再次q行q个E序Q你会发现结果是?FONT face="Times New Roman">fish bubble</FONT>”,也就是根据对象的cd调用了正的函数?/P> <P>那么当我们将<FONT face="Times New Roman">breathe()</FONT>声明?FONT face="Times New Roman">virtual</FONT>Ӟ在背后发生了什么呢Q?/P> <P>~译器在~译的时候,发现animalcM有虚函数Q此时编译器会ؓ每个包含虚函数的cdZ个虚表(即vtableQ,该表是一个一l数l,在这个数l中存放每个虚函数的地址。对于例1-2的程序,animal和fishc都包含了一个虚函数breathe()Q因此编译器会ؓq两个类都徏立一个虚表,如下图所C:</FONT><IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer; ZOOM: 90%" onclick=javascript:window.open(this.src); src="http://www.mybole.com.cn/bbs/UploadFile/2006-1/200611213817767.gif" onload="javascript:if(this.width>screen.width-500)this.style.width=screen.width-500;" border=0></P> <P align=center>?- 2 animalcdfishcȝ虚表</P> <P><FONT size=3><FONT face="Times New Roman">       </FONT>那么如何定位虚表呢?~译器另外还为每个类提供了一个虚表指针(?FONT face="Times New Roman">vptr</FONT>Q,q个指针指向了对象的虚表。在E序q行ӞҎ对象的类型去初始?FONT face="Times New Roman">vptr</FONT>Q从而让<FONT face="Times New Roman">vptr</FONT>正确的指向所属类的虚表,从而在调用虚函数时Q就能够扑ֈ正确的函数。对于例<FONT face="Times New Roman">1-2</FONT>的程序,׃<FONT face="Times New Roman">pAn</FONT>实际指向的对象类型是<FONT face="Times New Roman">fish</FONT>Q因?FONT face="Times New Roman">vptr</FONT>指向?FONT face="Times New Roman">fish</FONT>cȝ<FONT face="Times New Roman">vtable</FONT>Q当调用<FONT face="Times New Roman">pAn->breathe()</FONT>ӞҎ虚表中的函数地址扑ֈ的就?FONT face="Times New Roman">fish</FONT>cȝ<FONT face="Times New Roman">breathe()</FONT>函数?/FONT></P> <P><FONT size=3>正是׃每个对象调用的虚函数都是通过虚表指针来烦引的Q也决定了虚表指针的正初始化是非帔R要的。换句话_在虚表指针没有正初始化之前Q我们不能够去调用虚函数。那么虚表指针在什么时候,或者说在什么地方初始化呢?</FONT></P> <P><FONT size=3>{案是在构造函Cq行虚表的创建和虚表指针的初始化。还记得构造函数的调用序吗,在构造子cd象时Q要先调用父cȝ构造函敎ͼ此时~译器只“看C”父c,q不知道后面是否后还有承者,它初始化父类的虚表指针,该虚表指针指向父cȝ虚表。当执行子类的构造函数时Q子cȝ虚表指针被初始化Q指向自w的虚表。对于例<FONT face="Times New Roman">2-2</FONT>的程序来_?FONT face="Times New Roman">fish</FONT>cȝ<FONT face="Times New Roman">fh</FONT>对象构造完毕后Q其内部的虚表指针也p初始化ؓ指向<FONT face="Times New Roman">fish</FONT>cȝ虚表。在cd转换后,调用<FONT face="Times New Roman">pAn->breathe()</FONT>Q由?FONT face="Times New Roman">pAn</FONT>实际指向的是<FONT face="Times New Roman">fish</FONT>cȝ对象Q该对象内部的虚表指针指向的?FONT face="Times New Roman">fish</FONT>cȝ虚表Q因此最l调用的?FONT face="Times New Roman">fish</FONT>cȝ<FONT face="Times New Roman">breathe()</FONT>函数?/FONT></P> <P><FONT size=3>要注意:对于虚函数调用来_每一个对象内部都有一个虚表指针,该虚表指针被初始化ؓ本类的虚表。所以在E序中,不管你的对象cd如何转换Q但该对象内部的虚表指针是固定的Q所以呢Q才能实现动态的对象函数调用Q这是<FONT face="Times New Roman">C++</FONT>多态性实现的原理?/FONT></P> <P><FONT size=3>ȝQ基cL虚函敎ͼQ?/FONT></P> <P><FONT face="Times New Roman"><FONT size=3>1?/FONT>  </FONT><FONT size=3>每一个类都有虚表?/FONT></P> <P><FONT face="Times New Roman"><FONT size=3>2?/FONT>  </FONT><FONT size=3>虚表可以l承Q如果子cL有重写虚函数Q那么子c虚表中仍然会有该函数的地址Q只不过q个地址指向的是基类的虚函数实现。如果基c?FONT face="Times New Roman">3</FONT>个虚函数Q那么基cȝ虚表中就有三(虚函数地址Q,zcM会有虚表Q至有三项Q如果重写了相应的虚函数Q那么虚表中的地址׃改变Q指向自w的虚函数实现。如果派生类有自q虚函敎ͼ那么虚表中就会添加该V?/FONT></P> <P><FONT face="Times New Roman"><FONT size=3>3?/FONT>  </FONT><FONT size=3>zcȝ虚表中虚函数地址的排列顺序和基类的虚表中虚函数地址排列序相同?/FONT></P> <H1><FONT face="Times New Roman">3.   VC</FONT>视频W三?FONT face="Times New Roman">this</FONT>指针说明</H1> <P><FONT size=3>我在论坛?FONT face="Times New Roman">VC</FONT>教学视频版面发了帖子Q是模拟<FONT face="Times New Roman">MFC</FONT>cd的例子写的,主要是说明在基类的构造函C保存?FONT face="Times New Roman">this</FONT>指针是指向子cȝQ我们在看一下这个例子:</FONT></P> <DIV> <P align=center>?- 3</P></DIV> <P><FONT face="Times New Roman"><FONT size=3>#include <iostream.h><BR> <P></FONT></FONT> <P> <P> <P><FONT face="Times New Roman" size=3></FONT></P> <P> <P><FONT face="Times New Roman"><FONT size=3>class base;<BR> <P></FONT></FONT> <P> <P> <P><FONT face="Times New Roman" size=3></FONT></P> <P> <P><FONT face="Times New Roman"><FONT size=3>base * pbase;<BR> <P></FONT></FONT> <P> <P> <P><FONT face="Times New Roman" size=3></FONT></P> <P> <P><FONT face="Times New Roman"><FONT size=3>class base<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>{<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>public:<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       base()<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       {<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>              pbase=this;<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>              <BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       }<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       virtual void fn()<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       {<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>              cout<<"base"<<endl;<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       }<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>};<BR> <P></FONT></FONT> <P> <P> <P><FONT face="Times New Roman" size=3></FONT></P> <P> <P><FONT face="Times New Roman"><FONT size=3>class derived:public base<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>{<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       void fn()<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       {<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>              cout<<"derived"<<endl;<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       }<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>};<BR> <P></FONT></FONT> <P> <P> <P><FONT face="Times New Roman" size=3></FONT></P> <P> <P><FONT face="Times New Roman"><FONT size=3>derived aa;<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>void main()<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>{<BR> <P></FONT></FONT> <P> <P><FONT face="Times New Roman"><FONT size=3>       pbase->fn();<BR> <P></FONT></FONT> <P> <DIV> <P><FONT face="Times New Roman" size=3>}</FONT></P></DIV> <P><FONT size=3>我在<FONT face="Times New Roman">base</FONT>cȝ构造函C?FONT face="Times New Roman">this</FONT>指针保存?FONT face="Times New Roman">pbase</FONT>全局变量中。在定义全局对象<FONT face="Times New Roman">aa</FONT>Q即调用<FONT face="Times New Roman">derived aa;</FONT>Ӟ要调用基cȝ构造函敎ͼ先构造基cȝ部分Q然后是子类的部分,p两部分拼接出完整的对?FONT face="Times New Roman">aa</FONT>。这?FONT face="Times New Roman">this</FONT>指针指向的当然也是<FONT face="Times New Roman">aa</FONT>对象Q那么我?FONT face="Times New Roman">main()</FONT>函数中利?FONT face="Times New Roman">pbase</FONT>调用<FONT face="Times New Roman">fn()</FONT>Q因?FONT face="Times New Roman">pbase</FONT>实际指向的是<FONT face="Times New Roman">aa</FONT>对象Q?FONT face="Times New Roman">aa</FONT>对象内部的虚表指针指向的是自w的虚表Q最l调用的当然?FONT face="Times New Roman">derived</FONT>cM?FONT face="Times New Roman">fn()</FONT>函数?/FONT></P> <P><FONT size=3>在这个例子中Q由于我的疏忽,?FONT face="Times New Roman">derived</FONT>cM声明<FONT face="Times New Roman">fn()</FONT>函数Ӟ忘了?FONT face="Times New Roman">public</FONT>关键字,D声明Z<FONT face="Times New Roman">private</FONT>Q默认ؓ<FONT face="Times New Roman">private</FONT>Q,但通过前面我们所讲述的虚函数调用机制Q我们也明白了q个地方q不影响它输出正的l果。不知道q算不算<FONT face="Times New Roman">C++</FONT>的一?FONT face="Times New Roman">Bug</FONT>Q因函数的调用是在运行时定调用哪一个函敎ͼ所以编译器在编译时Qƈ不知?FONT face="Times New Roman">pbase</FONT>指向的是<FONT face="Times New Roman">aa</FONT>对象Q所以导致这个奇怪现象的发生。如果你直接?FONT face="Times New Roman">aa</FONT>对象去调用,׃对象cd是确定的Q注?FONT face="Times New Roman">aa</FONT>是对象变量,不是指针变量Q,~译器往往会采用早期绑定,在编译时定调用的函敎ͼ于是׃发现<FONT face="Times New Roman">fn()</FONT>是私有的Q不能直接调用。:Q?/FONT></P> <P><FONT size=3>许多学员在写q个例子Ӟ直接在基cȝ构造函C调用虚函敎ͼ前面已经说了Q在调用基类的构造函数时Q编译器只“看C”父c,q不知道后面是否后还有承者,它只是初始化父类的虚表指针,让该虚表指针指向父类的虚表,所以你看到l果当然不正。只有在子类的构造函数调用完毕后Q整个虚表才构徏完毕Q此时才能真正应?FONT face="Times New Roman">C++</FONT>的多态性?B>换句话说Q我们不要在构造函C去调用虚函数Q当然如果你只是惌用本cȝ函数Q也无所谓?/B><B> <P></B></FONT> <P> <H1><FONT face="Times New Roman">4.<FONT size=6>   </FONT></FONT>参考资料:</H1> <P><FONT size=3><FONT face="Times New Roman">1</FONT>、文章《在<FONT face="Times New Roman">VC6.0</FONT>中虚函数的实现方法》,作者:<FONT face="Times New Roman">backer </FONT>Q网址Q?/FONT></P> <P><FONT face="Times New Roman" size=3>http://www.mybole.com.cn/bbs/dispbbs.asp?boardid=4&id=1012&star=1</FONT></P> <P><FONT size=3><FONT face="Times New Roman">2</FONT>、书?FONT face="Times New Roman">C++</FONT>~程思想?FONT face="Times New Roman"> </FONT>机械工业出版C?/FONT></P> <H1><FONT face="Times New Roman">5.<FONT size=6>   </FONT></FONT>后记</H1> <P><FONT size=3>本想再写详细些,发现旉不够QL有很多事情,在加上水q也有限Q想惌是以后再说吧。不q我怿Q这些内容也能够帮助大家很好的理解了。也Ƣ迎|友能够l箋补充Q大家可以鼓动鼓?FONT face="Times New Roman">backer</FONT>Q让他从汇编的角度再l一个说明,哈哈Q别说我说的?/FONT></P><BR><img src ="http://www.shnenglu.com/richardzeng/aggbug/3924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/richardzeng/" target="_blank">Beginning to ~程</a> 2006-03-09 10:56 <a href="http://www.shnenglu.com/richardzeng/archive/2006/03/09/3924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.gallery2.cn" target="_blank">ٸ߳ҽоþþþþ</a>| <a href="http://www.56zhuanjia.com.cn" target="_blank">Ʒþþþþþþ</a>| <a href="http://www.xczg.org.cn" target="_blank">˾þô߽av</a>| <a href="http://www.r10211.cn" target="_blank">Ʒ18þþþþvr</a>| <a href="http://www.201324.cn" target="_blank">޹Ʒþһ</a>| <a href="http://www.vxfawh.cn" target="_blank">޾ҹþþþþ</a>| <a href="http://www.33k4.cn" target="_blank">þþƷ99þ㽶</a>| <a href="http://www.nxxdz.cn" target="_blank">þþ뾫ƷպĦ</a>| <a href="http://www.zusang.cn" target="_blank">޾Ʒһۺ99þ</a>| <a href="http://www.eiszar86.cn" target="_blank">ާѡþþþƷ9966</a>| <a href="http://www.sxzt888.cn" target="_blank">þþƷ99þ㽶</a>| <a href="http://www.njglqw.org.cn" target="_blank">þ99Ʒþþþþˮ</a>| <a href="http://www.iqyyh.cn" target="_blank">߳þѹۿ</a>| <a href="http://www.ds361.cn" target="_blank">þþƷWWW456C0M</a>| <a href="http://www.231it.cn" target="_blank">Ů˸߳þþýˮ</a>| <a href="http://www.xwbu.cn" target="_blank">޷?Vþò</a>| <a href="http://www.48zyai5o.cn" target="_blank">޾Ʒһþ</a>| <a href="http://www.skgv0713.cn" target="_blank">þùɫavѿ</a>| <a href="http://www.link133.cn" target="_blank">ŷɫ۾þþƷ</a>| <a href="http://www.jiangkangcmw.cn" target="_blank">ŮþþŮ</a>| <a href="http://www.dnf530.cn" target="_blank">þþƷwwwˬ</a>| <a href="http://www.hwwy.net.cn" target="_blank">þ޾ƷƵ</a>| <a href="http://www.hypcba.cn" target="_blank">Ʒۺþþþþ</a>| <a href="http://www.zzcjw.cn" target="_blank">þùƷһ</a>| <a href="http://www.76288.com.cn" target="_blank">Ļþþ</a>| <a href="http://www.ominimo.cn" target="_blank">þݺҹҹ96׽ </a>| <a href="http://www.baomintv.cn" target="_blank">þþþþùƷ</a>| <a href="http://www.zhouyimen.cn" target="_blank">ƷŮ߳׾þþ </a>| <a href="http://www.yywhqy.cn" target="_blank">þˬƬav</a>| <a href="http://www.miror.com.cn" target="_blank">þþƷAvӰƬ </a>| <a href="http://www.bxxlsl.cn" target="_blank">þùƷվ</a>| <a href="http://www.milanworld.cn" target="_blank">þþþþþþþþ</a>| <a href="http://www.hanfeng-foods.com.cn" target="_blank">þóСƵ</a>| <a href="http://www.engil.cn" target="_blank">þþƷվ</a>| <a href="http://www.0731dy.cn" target="_blank">ŷ鶹þþþþ</a>| <a href="http://www.ouseshi.cn" target="_blank">vaþþþͬ</a>| <a href="http://www.zqyipin.cn" target="_blank">þþþƷ</a>| <a href="http://www.cngit13.cn" target="_blank">þþù׮</a>| <a href="http://www.yzzdj.cn" target="_blank">ɫþþ99Ʒ91</a>| <a href="http://www.myswiss.cn" target="_blank">þWWW˳һƬ</a>| <a href="http://www.fengguan1688.cn" target="_blank">þҹӰ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>