青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

幽魂國度

 

2010年3月29日

CDC類對象的行為函數(shù)

(1)、常用的繪畫成員函數(shù):
     SetPixel():用指定的顏色在指定的坐標(biāo)畫一個點,返回值為RGB顏色值;
                        函數(shù)原型 COLORREF SetPixel( int x, int y, COLORREF crColor );
                                          COLORREF
SetPixel( POINT point, COLORREF crColor );
     MoveTo():移動當(dāng)前位置到指定的坐標(biāo),返回值為以前位置的坐標(biāo);
                        函數(shù)原型  CPoint MoveTo( int x, int y );
                                          
CPoint MoveTo( POINT point );
     LineTo():從當(dāng)前位置到指定位置畫一條直線,成功返回非0;
                        函數(shù)原型  BOOL LineTo( int x, int y ); 
                                          BOOL LineTo( POINT point );
     Polyline():從當(dāng)前位置,繪畫多條曲線,成功返回非0;
                        函數(shù)原型 BOOL Polyline( LPPOINT lpPoints, int nCount/*數(shù)目*/ );
     Rectangle():根據(jù)指定參數(shù)繪制一個矩形,成功返回非0;
                        函數(shù)原型  BOOL Rectangle( int x1, int y1, int x2, int y2 );
                                          B
OOL Rectangle( LPCRECT lpRect );
     Ellipse(): 根據(jù)指定的矩形繪制一個內(nèi)切橢圓,成功返回非0;
                        函數(shù)原型 BOOL Ellipse( int x1, int y1, int x2, int y2 );
                                         
BOOL Ellipse( LPCRECT lpRect );
     DrawIcon():在指定位置畫一個圖標(biāo),成功返回非0;
                        函數(shù)原型 BOOL DrawIcon( int x, int y, HICON hIcon );
                                          BOOL DrawIcon( POINT point, HICON hIcon );
(2)、有關(guān)文本處理的常用函數(shù):
     TextOut():在函數(shù)參數(shù)指定的位置顯示文本串。
                        函數(shù)原型 virtual BOOL TextOut( int x, int y, LPCTSTR lpszString, int nCount );
                                          BOOL TextOut( int x, int y, const CString& str );
     DrawText():在函數(shù)參數(shù)指定的矩形區(qū)域內(nèi)顯示文本串。
                        函數(shù)原型 virtual int DrawText( LPCTSTR lpszString, int nCount, LPRECT lpRect, UINT nFormat /*類型*/);
                                         
int DrawText( const CString& str, LPRECT lpRect, UINT nFormat );
     SetTextColor():設(shè)置顯示文本的顏色,返回當(dāng)前文本RGB顏色值;
                         函數(shù)原型 virtual COLORREF SetTextColor( COLORREF crColor );
    
GetTextColor():獲得當(dāng)前文本顏色; 函數(shù)原型 COLORREF GetTextColor( ) const;
     SetBkColor():設(shè)置顯示文本的背景顏色,返回當(dāng)前文本背景RGB顏色值;
                         函數(shù)原型 virtual COLORREF SetBkColor( COLORREF crColor );
     GetBkColor():獲得當(dāng)前文本背景顏色; 函數(shù)原型 COLORREF GetBkColor( ) const;
     SetBkMode():設(shè)置文本的背景模式,返回當(dāng)前背景模式值;
                         函數(shù)原型 int SetBkMode( int nBkMode /*模式*/); TRANSPARENT透明,OPAQUE 不透明  
     GetBkMode():獲得當(dāng)前文本背景模式; 函數(shù)原型 int GetBkMode( ) const;
    
SetTextAlign():設(shè)置顯示文本的對齊方式,成功返回非0;
                          函數(shù)原型  UINT SetTextAlign( UINT nFlags );
     GetTextAlign():獲得文本的對齊方式,函數(shù)原型 UINT GetTextAlign( ) const;

posted @ 2010-03-29 22:15 峰 閱讀(879) | 評論 (1)編輯 收藏

2010年1月21日

如何實現(xiàn)屬性表單

概述:創(chuàng)建一個屬性表單,首先創(chuàng)建一個CPropertySheet對象;為每一個屬性表單創(chuàng)建一個CPropertyPage對象,在CPropertySheet類中;在CPropertySheet類的構(gòu)造函數(shù)中添加AddPage函數(shù)添加每個屬性頁;最后在菜單函數(shù)中調(diào)用DoModal函數(shù)來顯示一個靜態(tài)屬性表單。屬性頁
是被添加屬性表單的,也就是說,屬性表單是屬性頁的父窗口。因此,可以通過GetParent()函數(shù)獲得屬性頁父窗口的指針,即屬性表單的
指針,但要經(jīng)過類型轉(zhuǎn)換
步驟:
1、創(chuàng)建一個或多個屬性頁,基類為CPropertyPage。
class CPropSet1 : public CPropertyPage
{
// Dialog Data
 //{{AFX_DATA(CPropSet1)
  enum { IDD = IDD_PROP_SET1 };
  int  m_MAXVALUEX2;
  int  m_MINVALUEX2;
 //}}AFX_DATA
}
2、建立CProp表單:基類為CPropertySheet。
CPropSheet::CPropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
 :CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
   AddPage(&m_propSet1); //決定page順序
   AddPage(&m_propSet2);
}
3、菜單函數(shù):
void CDataView::OnPropsheet()
{
 // TODO: Add your command handler code here
   CPropSheet propSheet("參數(shù)設(shè)置"); //表單名稱,其他為缺省變量
 
   propSheet.m_propSet1.m_MAXVALUEX2=m_XValueMax;
   propSheet.m_propSet1.m_MINVALUEX2=m_XValueMin;
 
 if( IDOK==propSheet.DoModal())
 {
    m_ChartCtrl1.EnableRefresh(false);
    m_XValueMax=propSheet.m_propSet1.m_MAXVALUEX2;
    m_XValueMin=propSheet.m_propSet1.m_MINVALUEX2;
    m_ChartCtrl1.GetBottomAxis()->SetMinMax(m_XValueMin,m_XValueMax);
    m_ChartCtrl1.EnableRefresh(true);
 }
}
4、建立向?qū)В?br>首先在調(diào)用屬性表單對象的DoModal函數(shù)之前,調(diào)用SetWizardMode函數(shù)。
    propSheet.SetWizardMode();
然后通過SetWizardButtons函數(shù)設(shè)置向?qū)υ捒蛏系陌粹o。
 ((CPropSheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);
 ((CPropSheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
 ((CPropSheet*)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);

注意點:需改文字種類和類型。

posted @ 2010-01-21 19:46 峰 閱讀(920) | 評論 (0)編輯 收藏

2009年12月31日

實現(xiàn)簡單打印預(yù)覽功能

打印預(yù)覽實現(xiàn)流程:
     首先調(diào)用CFormView::OnFilePrintPreview,再依次調(diào)用自己的所重寫的虛函數(shù)OnPreparePrinting(CPrintInfo* pInfo)、OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)、OnPrint(CDC* pDC, CPrintInfo* pInfo)、CFormView::OnPrint(pDC, pInfo);,當(dāng)關(guān)閉打印預(yù)覽時調(diào)用OnEndPrinting(CDC* pDC, CPrintInfo* pInfo)  ,結(jié)束打印。
部分代碼:
  ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
  BOOL CElectronValveView::OnPreparePrinting(CPrintInfo* pInfo)
{
 // default preparation
  pInfo->SetMinPage(1); //設(shè)置打印文件起始頁 
  pInfo->SetMaxPage(1); //設(shè)置打印文件終止頁
  return   DoPreparePrinting(pInfo);

void CElectronValveView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
 // TODO: add extra initialization before printing
  m_ChartCtrl.GetBottomAxis()->GetGrid()->SetColor(BlackColor);//設(shè)置柵格顏色為黑色,不然打印的時候太淡
  m_ChartCtrl.GetLeftAxis()->GetGrid()->SetColor(BlackColor);
}
void CElectronValveView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
 // TODO: add cleanup after printing
 m_ChartCtrl.GetBottomAxis()->GetGrid()->SetColor(BlueColor);//恢復(fù)顏色,不然控件中也是這個顏色了。
 m_ChartCtrl.GetLeftAxis()->GetGrid()->SetColor(BlueColor);
}
void CElectronValveView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
 // TODO: add customized printing code here
 CMainFrame* pMain=(CMainFrame *)AfxGetApp()->m_pMainWnd 
 CDC *pCurrentDC = GetDC();        // will have dimensions of the client area
 CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
 //獲得打印紙設(shè)備每英寸的像素數(shù),應(yīng)該是一樣的。
    CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
 //應(yīng)該是獲得屏幕的每英寸的像素數(shù),應(yīng)該是一樣的
 
 CSize m_PaperSize,m_LogicalPageSize;
 m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
 //把紙張所得的像素對應(yīng)的屏幕大小得到。
 m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4;
 m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4;
 
 //這里必須這樣設(shè),是為了和ChartCtrl中的打印對應(yīng)起來。
    pDC->SetMapMode(MM_ANISOTROPIC);
    pDC->SetWindowExt(m_LogicalPageSize);
    pDC->SetViewportExt(m_PaperSize);    
    pDC->SetWindowOrg(0, 0);   
 
 CRect rcClient,rcClient1;
 GetClientRect(&rcClient1); //得到的仍然是打印預(yù)覽顯示客戶區(qū)的大小
 rcClient=pInfo->m_rectDraw;//打印紙的客戶區(qū)
 double ratioX,ratioY;
 ratioX=(double)rcClient.right/(double)rcClient1.Width();
 ratioY=(double)rcClient.bottom/(double)rcClient1.Height();
 int nWid,left,right;
 CFont *pOldFont;
 CFont fnBig,fnBig1;
 CPen Pen,*OldPen;
 
 //畫主框
 Pen.CreatePen(PS_SOLID,2,RGB(0,0,0));
 OldPen=pDC->SelectObject(&Pen);
 pDC->Rectangle(20,20,m_LogicalPageSize.cx-20,m_LogicalPageSize.cy-20);
 pDC->SelectObject(OldPen);

 //畫標(biāo)題欄
 pDC->MoveTo(20,60);
 pDC->LineTo(m_LogicalPageSize.cx-20,60);
 pDC->MoveTo(20,85);
 pDC->LineTo(m_LogicalPageSize.cx-20,85);
 pDC->SelectObject(&Pen);
 pDC->MoveTo(20,110);
 pDC->LineTo(m_LogicalPageSize.cx-20,110);
 pDC->SelectObject(OldPen);
 pDC->MoveTo(196,60); 
 pDC->LineTo(196,110);
 pDC->MoveTo(390,60); 
 pDC->LineTo(390,110);

 //畫結(jié)果欄
 pDC->MoveTo(20,430); 
 pDC->LineTo(m_LogicalPageSize.cx-20,430);
 pDC->MoveTo(85,430); 
 pDC->LineTo(85,470);//測量結(jié)果1分界線豎線
 pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4+85,430);//開啟響應(yīng)時間分界線 
 pDC->LineTo((m_LogicalPageSize.cx-85-100)/4+85,470);
 pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4*2+85,430); 
 pDC->LineTo((m_LogicalPageSize.cx-85-100)/4*2+85,470);
 pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4*3+85,430); 
 pDC->LineTo((m_LogicalPageSize.cx-85-100)/4*3+85,470);
 pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4*4+85,430); 
 pDC->LineTo((m_LogicalPageSize.cx-85-100)/4*4+85,470);
 pDC->MoveTo(20,450); 
 pDC->LineTo(m_LogicalPageSize.cx-20,450);
 pDC->SelectObject(&Pen);
 pDC->MoveTo(20,470); 
 pDC->LineTo(m_LogicalPageSize.cx-20,470); 
 pDC->SelectObject(OldPen);

  //寫標(biāo)題
 fnBig.CreatePointFont(200,"黑體",pDC);
 pOldFont=pDC->SelectObject(&fnBig);
 
 nWid=rcClient1.Width();
 left=rcClient1.left;
 right=rcClient1.right;
 pDC->SetTextAlign(TA_CENTER);
 pDC->TextOut(m_LogicalPageSize.cx/2,30,"XXX性能測試報告");
 fnBig.DeleteObject();
 fnBig.CreatePointFont(110,"宋體",pDC);
 pOldFont=pDC->SelectObject(pOldFont);
 pOldFont=pDC->SelectObject(&fnBig);
 pDC->SetTextAlign(TA_LEFT);
 pDC->TextOut(25,67,"產(chǎn)品名稱:"+pMain->m_strProductName);
 pDC->TextOut(25,92,"產(chǎn)品圖號:"+pMain->m_strProductPictureNo);
 pDC->TextOut(201,67,"檢測時間:"+pMain->m_strMeasureTime0);
 pDC->TextOut(201,92,"生產(chǎn)廠家:"+pMain->m_strProductFactory);
 pDC->TextOut(395,67,"產(chǎn)品編號:"+pMain->m_strProductBianHao);
 pDC->TextOut(395,92,"檢 驗 員:"+pMain->m_strMeasurerName);

 CString aa;
 aa.Format("%d(ms)",m_iPreviousTime1);
 fnBig.DeleteObject();
 fnBig.CreatePointFont(85,"宋體",pDC);
 pDC->SelectObject(&fnBig);
 pDC->TextOut(25,420,"預(yù)置電信號時間:"+aa);
 aa.Format("%d",m_iCurveNumber1);
 pDC->TextOut(150,420,"曲線數(shù)量:"+aa);
 fnBig1.CreatePointFont(100,"宋體",pDC);
 pOldFont=pDC->SelectObject(&fnBig1);
 pDC->TextOut(25,455,"測試結(jié)果"); 
 pDC->TextOut(90,435,"開啟響應(yīng)時間(ms)");
 pDC->TextOut(120,455,m_strOpenResponseTime);
 pDC->TextOut((m_LogicalPageSize.cx-85-100)/4+85+5,435,"開啟換向時間(ms)");
 pDC->TextOut((m_LogicalPageSize.cx-85-100)/4+85+5+30,455,m_strOpenInvertTime);
 pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*2+85+5,435,"關(guān)閉響應(yīng)時間(ms)");
 pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*2+85+5+30,455,m_strCloseResponseTime);
 pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*3+85+5,435,"關(guān)閉換向時間(ms)");
 pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*3+85+5+30,455,m_strCloseInvertTime); 
 pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*4+85+10,435,"檢測結(jié)論");
 
 //最后一欄
 fnBig.DeleteObject();
 fnBig.CreatePointFont(130,"宋體",pDC);
 pDC->SelectObject(&fnBig);
 pDC->TextOut(m_LogicalPageSize.cx-180,m_LogicalPageSize.cy-20-20,"審核:");
 pDC->SetTextAlign(TA_LEFT);

 CPoint offset(16,110);
 m_ChartCtrl.Print1(offset,pDC,pInfo,0);//調(diào)用chart類來畫表格和曲線
 fnBig.DeleteObject();

 CFormView::OnPrint(pDC, pInfo);
}
本程序利用ChartCtrl來實現(xiàn)繪制表格和曲線。

posted @ 2009-12-31 15:26 峰 閱讀(1285) | 評論 (0)編輯 收藏

2009年12月30日

簡述如何實現(xiàn)簡單預(yù)覽

步驟1:添加新類CDIBStatic,類型為MFC Class,基類為CStatic。
步驟2:在工程中加入CPictureObj.h和CPictureObj.cpp,及CIstream.h和CIstream.cpp。
步驟3:在類CDIBStatic加入頭文件#include "PictureObj.h",添加變量CPictureObj* m_pPicObj;,用于讀取和顯示。CPictureObj中封裝了IPicture接口。
步驟4:新建一Dialog,加入控件picture,類型為MFC Class,基類為CfileDlg。
部分代碼:
CDIBStatic源代碼:
OOL CDIBStatic::LoadDib(LPCTSTR lpszFileName)//讀取
{
 try//利用try語句當(dāng)文件第一次打開時lpszFileName會出錯,在catch中捕獲將其設(shè)置為NULL
lpszFileName = lpszFileName;
  // 確保文件存在并能打開
  CFile file(lpszFileName, CFile::modeRead);
  file.Close();

// 創(chuàng)建圖像顯示的對象并讀入圖像文件
  m_pPicObj = new CPictureObj;
  if(!m_pPicObj->Load(lpszFileName))
  {
   // 讀入文件失敗,清除對象
   m_pPicObj = NULL;
   delete m_pPicObj;
   // 清除顯示的圖像并顯示錯誤提示
   PaintDib(IsValidDib());
   return FALSE;
  }
  PaintDib(IsValidDib());
  return TRUE;
 }
 catch (CFileException* e)
 {
  m_lpszFileName = NULL;
  PaintDib(IsValidDib());
  e->Delete();
  return FALSE;
 }
}

void CDIBStatic::PaintDib(BOOL bDibValid)//顯示
{
 ASSERT_VALID(this);
 ClearDib(); // 清除以前的圖像
  
 CRect PaintRect;
 // 獲得顯示區(qū)域
 GetClientRect(&PaintRect);   
 PaintRect.InflateRect(-1, -1);
 CClientDC dc(this);

 if (bDibValid && m_bPreview)
 {
  CSize size = m_pPicObj->GetSize(&dc);
  int nDestX, nDestY, nDestWidth, nDestHeight;
  if ((DWORD)size.cx < (DWORD)PaintRect.Width() && (DWORD)size.cy < (DWORD)PaintRect.Height())
  { // 圖像尺寸小于顯示區(qū)域?qū)D像顯示在中間
   nDestX = PaintRect.left + (PaintRect.Width() - size.cx)/2;
   nDestY = PaintRect.top + (PaintRect.Height() - size.cy)/2;
   nDestWidth = size.cx;
   nDestHeight = size.cy;
  }
  else
  { // 圖像尺寸大于顯示區(qū)域,進行比例縮放
   if ((PaintRect.Width()/(float)size.cx) <= (PaintRect.Height()/(float)size.cy))
   { // 寬度限制
    nDestWidth = PaintRect.Width();
    nDestHeight = (nDestWidth*size.cy) / size.cx;
    nDestX = PaintRect.left;
    nDestY = PaintRect.top + (PaintRect.Height() - nDestHeight) /2;
   }
   else
   { // 高度限制  
    nDestHeight = PaintRect.Height();
    nDestWidth = (nDestHeight*size.cx) / size.cy;
    nDestX = PaintRect.left + (PaintRect.Width() - nDestWidth) /2;
    nDestY = PaintRect.top;
   }
  }

  // 獲得圖像的顯示位置和大小
  CRect RectDest(nDestX, nDestY, nDestX+nDestWidth, nDestY+nDestHeight);
  // 顯示圖像
  m_pPicObj->Draw(&dc,&RectDest,&RectDest);
  // 給圖像加一外框
  CBrush*  pOldBrush  = (CBrush*)dc.SelectStockObject(NULL_BRUSH);  
  dc.Rectangle(RectDest);
  if(NULL != pOldBrush)  { dc.SelectObject(pOldBrush);  }
 }
 else
 {
  // 顯示錯誤提示信息
  CString strText = "不能識別的文件格式!";
  if( m_lpszFileName == NULL || strlen(m_lpszFileName) <= 0 )
  {
   strText = "沒有選擇文件!";
  }
  if( !m_bPreview )
  {
   strText = "";
  }
  dc.DrawText(strText, strText.GetLength(), &PaintRect, DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_END_ELLIPSIS);
 }
  
 return;
}

HBRUSH CDIBSatic::CtlColor(CDC* pDC, UINT nCtlColor)//用于重繪
{
 // TODO: Change any attributes of the DC here
 PaintDib(IsValidDib());
 return (HBRUSH)GetStockObject(NULL_BRUSH);
}
BOOL IsValidDib() const { return (m_pPicObj && m_pPicObj->m_pPict); }
void CDIBSatic::ClearDib()//清除圖片
{
 ASSERT_VALID(this);
 
 CClientDC dc(this);
 CRect rectPaint;
   
 GetClientRect(&rectPaint);   
 rectPaint.InflateRect(-1,-1);
    
 CBrush* pBrushWhite; //白畫刷
 pBrushWhite = CBrush::FromHandle((HBRUSH)::GetStockObject(WHITE_BRUSH));
   
 dc.FillRect(&rectPaint, pBrushWhite);
}
void RemoveDib() { m_lpszFileName = NULL; delete m_pPicObj; m_pPicObj = NULL; PaintDib(IsValidDib()); }
 void SetPreview(BOOL bPreview) { m_bPreview = bPreview; PaintDib(IsValidDib()); }
CPreviewFileDlg源代碼:
BOOL CPreviewFileDlg::OnInitDialog()
{
 CFileDialog::OnInitDialog();
 m_DIBStaticCtrl.SubclassDlgItem(IDC_IMAGE, this);
 CWnd* pParent = GetParent();
 CRect rcParent;
 pParent->GetClientRect(&rcParent);
 CRect rcPrev;
 GetDlgItem(IDC_PREVIEW)->GetClientRect(&rcPrev); //復(fù)選框
 CRect rc;
 m_DIBStaticCtrl.GetClientRect(&rc);
 int height = rc.Height();
 rc.top = rcPrev.bottom - 10;//圖像框設(shè)置
 rc.bottom = rc.top + height ;
 rc.left = 50;
 rc.right = rcParent.Width() - rc.left;
 m_DIBStaticCtrl.MoveWindow(&rc, true);

 GetDlgItem(IDC_PREVIEW)->SendMessage(BM_SETCHECK, (m_bPreview) ? 1 : 0);
 
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}
void CPreviewFileDlg::OnFileNameChange()
{
 CFileDialog::OnFileNameChange();
 if (m_bPreview)
 {
  m_DIBStaticCtrl.SetPreview(m_bPreview);//顯示圖片
  m_DIBStaticCtrl.LoadDib(GetPathName()); //加載
 }

}//當(dāng)點擊文件時調(diào)用
void CPreviewFileDlg::OnFolderChange()
{
 CFileDialog::OnFolderChange();
 m_DIBStaticCtrl.RemoveDib();//清除
}
菜單欄源代碼:
void CPreviewDlg::OnPreview()
{
 // TODO: Add extra validation here
    static char BASED_CODE szFilter[] = "Bitmap(*.bmp)|*.bmp|JPEG(*.jpg)|*.jpg|GIF(*.gif)|*.gif|WMF(*.wmf)|*.wmf|ICON(*.ico)|*.ico||";
 CString strDefName;

 char szPath[MAX_PATH];//最大目錄大小
 
    CPreviewFileDlg FileDlg(TRUE,"*.*",NULL,
                        OFN_FILEMUSTEXIST|OFN_NONETWORKBUTTON|
                        OFN_PATHMUSTEXIST,szFilter);
 FileDlg.m_ofn.lpstrInitialDir = szPath;
    if( FileDlg.DoModal() != IDOK )
  return;

    // To get the selected file's path and name
    CString strFileName;
    strFileName = FileDlg.GetPathName();

    if(strFileName.IsEmpty())
    {
  return;
 }
}

posted @ 2009-12-30 21:03 峰 閱讀(623) | 評論 (0)編輯 收藏

2009年12月3日

淺談malloc()和free()

 

一、malloc()free()的基本概念以及基本用法:

1、函數(shù)原型及說明:

void *malloc(long NumBytes)

該函數(shù)分配了NumBytes個字節(jié),并返回了指向這塊內(nèi)存的指針。如果分配失敗,則返回一個空指針(NULL)。

關(guān)于分配失敗的原因,應(yīng)該有多種,比如說空間不足就是一種。

void free(void *FirstByte)

該函數(shù)是將之前用malloc分配的空間還給程序或者是操作系統(tǒng),也就是釋放了這塊內(nèi)存,讓它重新得到自由。

2、函數(shù)的用法:

      其實這兩個函數(shù)用起來倒不是很難,也就是malloc()之后覺得用夠了就甩了它把它給free()了,舉個簡單例子:

程序代碼:

         // Code...

         float *YValue;

         YValue=(float *)malloc(DataNumberMax*sizeof(float));  //動態(tài)分配內(nèi)存

         if (NULL == YValue)   exit (1);

         gets(YValue);

         // code...

         free(YValue);

         YValue= NULL;

         // code...

     就是這樣!當(dāng)然,具體情況要具體分析以及具體解決。比如說,你定義了一個指針,在一個函數(shù)里申請了一塊內(nèi)存然后通過函數(shù)返回傳遞給這個指針,那么也許釋放這塊內(nèi)存這項工作就應(yīng)該留給其他函數(shù)了。

3、關(guān)于函數(shù)使用需要注意的一些地方:

A、申請了內(nèi)存空間后,必須檢查是否分配成功。

B、當(dāng)不需要再使用申請的內(nèi)存時,記得釋放;釋放后應(yīng)該把指向這塊內(nèi)存的指針指向NULL,防止程序后面不小心使用了它。

C、這兩個函數(shù)應(yīng)該是配對。如果申請后不釋放就是內(nèi)存泄露;如果無故釋放那就是什么也沒有做。釋放只能一次,如果釋放兩次及兩次以上會出現(xiàn)錯誤(釋放空指針例外,釋放空指針其實也等于啥也沒做,所以釋放空指針釋放多少次都沒有問題)。

D、雖然malloc()函數(shù)的類型是(void *),任何類型的指針都可以轉(zhuǎn)換成(void *),但是最好還是在前面進行強制類型轉(zhuǎn)換,因為這樣可以躲過一些編譯器的檢查。

二、malloc()到底從哪里得來了內(nèi)存空間:

 

1 malloc()到底從哪里得到了內(nèi)存空間? 答案是從堆里面獲得空間。也就是說函數(shù)返回的指針是指向堆里面的一塊內(nèi)存。操作系統(tǒng)中有一個記錄空閑內(nèi)存地址的鏈表。當(dāng)操作系統(tǒng)收到程序的申請時,就會遍歷該鏈表,然后就尋找第一個空間大于所申請空間的堆結(jié)點,然后就將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點的空間分配給程序。就是這樣!

2、什么是堆:堆是大家共有的空間,分全局堆和局部堆。全局堆就是所有沒有分配的空間,局部堆就是用戶分配的空間。堆在操作系統(tǒng)對進程 初始化的時候分配,運行過程中也可以向系統(tǒng)要額外的堆,但是記得用完了要還給操作系統(tǒng),要不然就是內(nèi)存泄漏。

    什么是棧:棧是線程獨有的,保存其運行狀態(tài)和局部自動變量的。棧在線程開始的時候初始化,每個線程的?;ハ嗒毩ⅰC總€函數(shù)都有自己的棧,棧被用來在函數(shù)之間傳遞參數(shù)。操作系統(tǒng)在切換線程的時候會自動的切換棧,就是切換SS/ESP寄存器。??臻g不需要在高級語言里面顯式的分配和釋放。

    通過上面對概念的描述,可以知道:

    棧是由編譯器自動分配釋放,存放函數(shù)的參數(shù)值、局部變量的值等。操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

    堆一般由程序員分配釋放,若不釋放,程序結(jié)束時可能由OS回收。注意這里說是可能,并非一定。所以我想再強調(diào)一次,記得要釋放!

所以,舉個例子,如果你在函數(shù)上面定義了一個指針變量,然后在這個函數(shù)里申請了一塊內(nèi)存讓指針指向它。實際上,這個指針的地址是在棧上,但是它所指向的內(nèi)容卻是在堆上面的!這一點要注意!所以,再想想,在一個函數(shù)里申請了空間后,比如說下面這個函數(shù):

程序代碼:

    // code...

        void Function(void)

        {

         char *p = (char *)malloc(100 * sizeof(char));

     }

    就這個例子,千萬不要認為函數(shù)返回,函數(shù)所在的棧被銷毀指針也跟著銷毀,申請的內(nèi)存也就一樣跟著銷毀了!這絕對是錯誤的!因為申請的內(nèi)存在堆上,而函數(shù)所在的棧被銷毀跟堆完全沒有啥關(guān)系。所以,還是那句話:記得釋放!

 

3、free()到底釋放了什么

    free()釋放的是指針指向的內(nèi)存!注意!釋放的是內(nèi)存,不是指針!這點非常非常重要!指針是一個變量,只有程序結(jié)束時才被銷毀。釋放了內(nèi)存空間后,原來指向這塊空間的指針還是存在!只不過現(xiàn)在指針指向的內(nèi)容的垃圾,是未定義的,所以說是垃圾。因此,前面我已經(jīng)說過了,釋放內(nèi)存后把指針指向NULL,防止指針在后面不小心又被解引用了。非常重要啊這一點!

 

三、malloc()以及free()的機制:

    事實上,仔細看一下free()的函數(shù)原型,也許也會發(fā)現(xiàn)似乎很神奇,free()函數(shù)非常簡單,只有一個參數(shù),只要把指向申請空間的指針傳遞

 

free()中的參數(shù)就可以完成釋放工作!這里要追蹤到malloc()的申請問題了。申請的時候?qū)嶋H上占用的內(nèi)存要比申請的大。因為超出的空間是用來記錄對這塊內(nèi)存的管理信息。

malloc()申請的空間實際我覺得就是分了兩個不同性質(zhì)的空間。一個就是用來記錄管理信息的空間,另外一個就是可用空間了。而用來記錄管理信息的實際上是一個結(jié)構(gòu)體。在C語言中,用結(jié)構(gòu)體來記錄同一個對象的不同信息是

下面看看這個結(jié)構(gòu)體的原型:

程序代碼:

    struct mem_control_block {

     int is_available;     //這是一個標(biāo)記?

     int size;             //這是實際空間的大小

     };

    對于size,這個是實際空間大小。這里其實我有個疑問,is_available是否是一個標(biāo)記?因為我看了free()的源代碼之后對這個變量感覺有點納悶(源代碼在下面分析)。這里還請大家指出!

    所以,free()就是根據(jù)這個結(jié)構(gòu)體的信息來釋放malloc()申請的空間!而結(jié)構(gòu)體的兩個成員的大小我想應(yīng)該是操作系統(tǒng)的事了。但是這里有一個問題,malloc()申請空間后返回一個指針應(yīng)該是指向第二種空間,也就是可用空間!不然,如果指向管理信息空間的話,寫入的內(nèi)容和結(jié)構(gòu)體的類型有可能不一致,或者會把管理信息屏蔽掉,那就沒法釋放內(nèi)存空間了,所以會發(fā)生錯誤?。ǜ杏X自己這里說的是廢話)

 

    好了!下面看看free()的源代碼,我自己分析了一下,覺得比起malloc()的源代碼倒是容易簡單很多。只是有個疑問,下面指出!

程序代碼:

    // code...

   

        void free(void *ptr) 

     {

             struct mem_control_block *free;

             free = ptr - sizeof(struct mem_control_block);

             free->is_available = 1;

             return;

     }

    看一下函數(shù)第二句,這句非常重要和關(guān)鍵。其實這句就是把指向可用空間的指針倒回去,讓它指向管理信息的那塊空間,因為這里是在值上減去了一個結(jié)構(gòu)體的大??!后面那一句free->is_available = 1;我有點納悶!我的想法是:這里is_available應(yīng)該只是一個標(biāo)記而已!因為從這個變量的名稱上來看,is_available 翻譯過來就是“是可以用”。不要說我土!我覺得變量名字可以反映一個變量的作用,特別是嚴(yán)謹?shù)拇a。這是源代碼,所以我覺得絕對是嚴(yán)謹?shù)模。∵@個變量的值是1,表明是可以用的空間!只是這里我想了想,如果把它改為0或者是其他值不知道會發(fā)生什么事?!但是有一點我可以肯定,就是釋放絕對不會那么順利進行!因為這是一個標(biāo)記!

 

    當(dāng)然,這里可能還是有人會有疑問,為什么這樣就可以釋放呢??我剛才也有這個疑問。后來我想到,釋放是操作系統(tǒng)的事,那么就free()這個源代碼來看,什么也沒有釋放,對吧?但是它確實是確定了管理信息的那塊內(nèi)存的內(nèi)容。所以,free()只是記錄了一些信息,然后告訴操作系統(tǒng)那塊內(nèi)存可以去釋放,具體怎么告訴操作系統(tǒng)的我不清楚,但我覺得這個已經(jīng)超出了我這篇文章的討論范圍了。

 

    那么,我之前有個錯誤的認識,就是認為指向那塊內(nèi)存的指針不管移到那塊內(nèi)存中的哪個位置都可以釋放那塊內(nèi)存!但是,這是大錯特錯!釋放是不可以釋放一部分的!首先這點應(yīng)該要明白。而且,從 free()的源代碼看,ptr只能指向可用空間的首地址,不然,減去結(jié)構(gòu)體大小之后一定不是指向管理信息空間的首地址。所以,要確保指針指向可用空間的首地址!
程序代碼:
float *YValuePoint;
while ( !feof(file) && i<DataNumberMax)  //讀數(shù)
  {
   fscanf(file,"%f ",&data);      
   YValue[i]=data;
   sum+=YValue[i];
   pLineSerie->AddPoint(XValue++,YValue[i]);
   i++;
  }
  average=sum/DataNumberMax;
  max=*YValue;
  min=*(YValue+2);
 YValuePoint=YValue; //保存首地址
  for(int j=0;j<DataNumberMax;j++)
  {
      if(max <* YValue)
   {
        max =* YValue;
   }
   else
   {
    if(min > *YValue)  min = *YValue;
   }
   YValue++;              //YValue地址值+1
  }

  free(YValuePoint);  //釋放內(nèi)存,釋放從該內(nèi)存空間的首地址開始

posted @ 2009-12-03 11:50 峰 閱讀(413) | 評論 (0)編輯 收藏

2009年11月28日

鉤子

     摘要: HHOOK SetWindowsHookEx(                                    //裝載一個...  閱讀全文

posted @ 2009-11-28 16:01 峰 閱讀(1448) | 評論 (0)編輯 收藏

2009年11月22日

指針的指針

指向另一指針的指針:轉(zhuǎn)自風(fēng)過無痕博客
 

一. 回顧指針概念:
早在本系列第二篇中我就對指針的實質(zhì)進行了闡述。今天我們又要學(xué)習(xí)一個叫做指向另一指針地址的指針。讓我們先回顧一下指針的概念吧!
當(dāng)我們程序如下申明變量:
short int i;
char a;
short int * pi;
程序會在內(nèi)存某地址空間上為各變量開辟空間,如下圖所示。
內(nèi)存地址→6     7      8     9     10     11    12    13     14    15
-------------------------------------------------------------------------------------
…  |     |      |      |      |      |       |      |      |      |  
-------------------------------------------------------------------------------------
    |short int i |char a|      |short int * pi|
圖中所示中可看出:
i 變量在內(nèi)存地址5的位置,占兩個字節(jié)。
a變量在內(nèi)存地址7的位置,占一個字節(jié)。
pi變量在內(nèi)存地址9的位置,占兩個字節(jié)。(注:pi 是指針,我這里指針的寬度只有兩個字節(jié),32位系統(tǒng)是四個字節(jié))
接下來如下賦值:
i=50;
pi=&i;
經(jīng)過上在兩句的賦值,變量的內(nèi)存映象如下:
內(nèi)存地址→6     7      8     9     10     11    12    13      14     15
--------------------------------------------------------------------------------------
…  |    50      |      |      |    6         |      |      |       |  
--------------------------------------------------------------------------------------
    |short int i |char a|      |short int * pi|
看到?jīng)]有:短整型指針變量pi的值為6,它就是I變量的內(nèi)存起始地址。所以,這時當(dāng)我們對*pi進行讀寫操作時,其實就是對i變量的讀寫操作。如:
*pi=5;   //就是等價于I=5;

二. 指針的地址與指向另一指針地址的指針
在上一節(jié)中,我們看到,指針變量本身與其它變量一樣也是在某個內(nèi)存地址中的,如pi的內(nèi)存起始地址是10。同樣的,我們也可能讓某個指針指向這個地址。
看下面代碼:
short int * * ppi;    //這是一個指向指針的指針,注意有兩個*號
ppi=pi
第一句:short int * * ppi;——申明了一個指針變量ppi,這個ppi是用來存儲(或稱指向)一個short int * 類型指針變量的地址。
第二句:&pi那就是取pi的地址,ppi=pi就是把pi的地址賦給了ppi。即將地址值10賦值給ppi。如下圖:
內(nèi)存地址→6     7      8     9     10     11    12    13       14    15
------------------------------------------------------------------------------------
…  |    50     |      |      |      6       |       10      |      |  
------------------------------------------------------------------------------------
    |short int i|char a|      |short int * pi|short int ** ppi|
從圖中看出,指針變量ppi的內(nèi)容就是指針變量pi的起始地址。于是……
ppi的值是多少呢?——10。
*ppi的值是多少呢?——6,即pi的值。
**ppi的值是多少呢?——50,即I的值,也是*pi的值。
呵呵!不用我說太多了,我相信你應(yīng)明白這種指針了吧!

三. 一個應(yīng)用實例
1. 設(shè)計一個函數(shù):void find1(char array[], char search, char * pi)
要求:這個函數(shù)參數(shù)中的數(shù)組array是以0值為結(jié)束的字符串,要求在字符串a(chǎn)rray中查找字符是參數(shù)search里的字符。如果找到,函數(shù)通過第三個參數(shù)(pa)返回值為array字符串中第一個找到的字符的地址。如果沒找到,則為pa為0。
設(shè)計:依題意,實現(xiàn)代碼如下。
void find1(char array[] , char search, char * pa)
{
   int i;
   for (i=0;*(array+i)!=0;i++)
   {
      if (*(array+i)==search)
      {
        pa=array+i
        break;
      }
      else if (*(array+i)==0)
      {
        pa=0;
        break;
      }
   }
}
你覺得這個函數(shù)能實現(xiàn)所要求的功能嗎?
調(diào)試:
我下面調(diào)用這個函數(shù)試試。
void main()
{
  char str[]={“afsdfsdfdf\0”};  //待查找的字符串
  char a=’d’;   //設(shè)置要查找的字符
  char * p=0;  //如果查找到后指針p將指向字符串中查找到的第一個字符的地址。
  find1(str,a,p);  //調(diào)用函數(shù)以實現(xiàn)所要操作。
  if (0==p )
  {
     printf (“沒找到!\n”);//1.如果沒找到則輸出此句
  }
  else
  {
     printf(“找到了,p=%d”,p);  //如果找到則輸出此句
  }
}
分析:
上面代碼,你認為會是輸出什么呢?
運行試試。
唉!怎么輸出的是:沒有找到!
而不是:找到了,……。
明明a值為’d’,而str字符串的第四個字符是’d’,應(yīng)該找得到呀!
再看函數(shù)定義處:void find1(char array[] , char search, char * pa)
看調(diào)用處:find1(str,a,p);
依我在第五篇的分析方法,函數(shù)調(diào)用時會對每一個參數(shù)進行一個隱含的賦值操作。
整個調(diào)用如下:
   array=str;
   search=a;
   pa=p;    //請注意:以上三句是調(diào)用時隱含的動作。
   int i;
   for (i=0;*(array+i)!=0;i++)
   {
      if (*(array+i)==search)
      {
        pa=array+i
        break;
      }
      else if (*(array+i)==0)
      {
        pa=0;
        break;
      }
   }
哦!參數(shù)pa與參數(shù)search的傳遞并沒有什么不同,都是值傳遞嘛(小語:地址傳遞其實就是地址值傳遞嘛)!所以對形參變量pa值(當(dāng)然值是一個地址值)的修改并不會改變實參變量p值,因此p的值并沒有改變(即p的指向并沒有被改變)。
(如果還有疑問,再看一看《函數(shù)參數(shù)的傳遞》了。)
修正:
void find2(char [] array, char search, char ** ppa)
{
   int i;
   for (i=0;*(array+i)!=0;i++)
   {
      if (*(array+i)==search)
      {
        *ppa=array+i
        break;
      }
      else if (*(array+i)==0)
      {
        *ppa=0;
        break;
      }
   }
}
主函數(shù)的調(diào)用處改如下:
  find2(str,a,&p);  //調(diào)用函數(shù)以實現(xiàn)所要操作。
再分析:
這樣調(diào)用函數(shù)時的整個操作變成如下:
   array=str;
   search=a;
   ppa=&p;    //請注意:以上三句是調(diào)用時隱含的動作。
   int i;
   for (i=0;*(array+i)!=0;i++)
   {
      if (*(array+i)==search)
      {
        *ppa=array+i
        break;
      }
      else if (*(array+i)==0)
      {
        *ppa=0;
        break;
      }
   }
看明白了嗎?
ppa指向指針p的地址。
對*ppa的修改就是對p值的修改。
下面看一下指向指針變量的指針變量怎樣正確引用。
用指向指針的指針變量訪問一維和二維數(shù)組。

#include<stdio.h>
#include<stdlib.h>
main()
{
int a[3],b[2][2],*p1,*p2,**p3,i,j;

printf("請輸入一維數(shù)組的值:\n");
for(i=0;i<3;i++)
scanf("%d",&a[i]);/*一維數(shù)組的輸入*/

printf("請輸入二維數(shù)組的值:\n");
for(i=0;i<2;i++)
for(j=0;j<2;j++)
scanf("%d",&b[i][j]);/*二維數(shù)組輸入*/

printf("用指針輸出一維數(shù)組:\n");
for(p1=a,i=0;i<3;i++)     /* 用指針輸出一維數(shù)組*/
{
    printf("%4d",*(p1+i));
}
printf("\n");

printf("用指向指針的指針變量輸出一維數(shù)組(1):\n");
for(p1=a,p3=&p1,i=0;i<3;i++)
printf("%4d",*(*p3+i));/*用指向指針的指針變量輸出一維數(shù)組*/
printf("\n");
printf("用指向指針的指針變量輸出一維數(shù)組(2):\n");
for(p1=a;p1-a<3;p1++)/*用指向指針的指針變量輸出一維數(shù)組*/
{
p3=&p1;
printf("%4d",**p3);
}
printf("\n");

printf("用指針輸出二維數(shù)組:\n");
for(i=0;i<2;i++)   /*用指針輸出二維數(shù)組*/
{
   p2=b[i] ;
   for(int j=0;j<2;j++)
  {
    printf("%4d",*(p2+j)) ;
  }
}
printf("\n");

printf("用指向指針的指針變量輸出二維數(shù)組(1):\n");
for(i=0;i<2;i++)/*用指向指針的指針變量輸出二維數(shù)組*/
{
p2=b[i];
p3=&p2;
for(j=0;j<2;j++)
printf("%4d",*(*p3+j));

利用指向指針的指針變量對二維字符數(shù)組的訪問。

#include<stdio.h>
#include<stdlib.h>
main()
{
int i;
char * ptr;
static char c[][16]={"clanguage","fox","computer","homepage"};
/*二維字符數(shù)組*/
static char *cp[]={c[0],c[1],c[2],c[3]};/*指針數(shù)組*/
static char **cpp;/*指向字符指針的指針變量*/
cpp=cp;/*將指針數(shù)組的首地址傳遞給指向字符指針的指針變量*/


for(i=0;i<4;i++)/*按行輸出字符串*/
printf("%s\n",*cpp++);
printf("-----------\n");

for(i=0;i<4;i++)/*按行輸出字符串*/
{
cpp=&cp[i];
printf("%s\n",*cpp);
}
printf("-----------\n");

 
 for(i=0;i<4;i++)
 {
    ptr=c[i];
    printf("%s",ptr);
    printf("\n");
 }
 

}

}
printf("\n");

 printf("用指向指針的指針變量輸出二維數(shù)組(2):\n");
for(i=0;i<2;i++)/*用指向指針的指針變量輸出二維數(shù)組*/
{
p2=b[i];
for(p2=b[i];p2-b[i]<2;p2++)
{
p3=&p2;
printf("%4d",**p3);
}
printf("\n");
}

}

posted @ 2009-11-22 22:31 峰 閱讀(364) | 評論 (0)編輯 收藏

2009年11月21日

C++中的接口與實現(xiàn)

        所謂接口繼承,就是派生類只繼承函數(shù)的接口,也就是聲明;而實現(xiàn)繼承,就是派生類同時繼承函數(shù)的接口和實現(xiàn)。
       我們都很清楚C++中有幾個基本的概念,虛函數(shù)、純虛函數(shù)、非虛函數(shù)。
       虛函數(shù)
       C++實現(xiàn)運行中的多態(tài)性是通過虛函數(shù)實現(xiàn)的,而虛函數(shù)必須存在于繼承環(huán)境下。
       因此,虛函數(shù)是指一個類中你希望進行重載的成員函數(shù),當(dāng)你用一個基類指針或引用指向一個繼承類對象的時候,你調(diào)用一個虛函數(shù),實際調(diào)用的是繼承類的成員函數(shù)。虛函數(shù)用來表現(xiàn)基類和派生類的成員函數(shù)之間的一種關(guān)系。虛函數(shù)的定義在基類中進行,在需要定義為虛函數(shù)的成員函數(shù)的聲明前冠以關(guān)鍵字,如 virtual void func() 。 基類中的某個成員函數(shù)被聲明為虛函數(shù)后,此虛函數(shù)就可以在一個或多個派生類中被重新定義. 在派生類中重新定義時,其函數(shù)原型,包括返回類型、函數(shù)名、參數(shù)個數(shù)、參數(shù)類型及參數(shù)的先后順序,都必須與基類中的原型完全相同。
        虛函數(shù)是重載的一種表現(xiàn)形式,是一種動態(tài)的重載方式。
       只有類的普通成員函數(shù)可以定義為虛函數(shù),全局函數(shù)及靜態(tài)成員函數(shù)(類擁有)不能聲明為虛函數(shù)。
       純虛函數(shù):
        純虛函數(shù)在基類中沒有定義且只能在基類中定義,但未給出具體的函數(shù)定義體(實現(xiàn)),它們被初始化為0。任何用純虛函數(shù)派生的類,都要自己提供該函數(shù)的具體實現(xiàn)。
         定義純虛函數(shù):virtual void func() = 0;
         定義了純虛函數(shù)的類被稱之為抽象類。抽象類定義一族派生類的共同接口,而接口的完整實現(xiàn),即純虛函數(shù)的函數(shù)體,由派生類自己定義。
例://class Shape
       public:
                 virtual void area()=0; // 純虛函數(shù)
        //class Tringle : public Shape  //公有繼承
       public:
                void area() {//}                /接口與實現(xiàn)
         抽象類可以有多個純虛函數(shù),也可以定義其他虛函數(shù)。若派生類沒有重新定義純虛函數(shù),那么該派生類也稱之為純虛函數(shù)。
         純虛函不需要定義其實際操作,它的存在只是為了在派生類中被重新定義,只是提供一個多態(tài)接口。
       非虛函數(shù)
       一般成員函數(shù),無virtual關(guān)鍵字修飾。
        至于為什么要定義這些函數(shù),我們可以將虛函數(shù)、純虛函數(shù)和非虛函數(shù)的功能與接口繼承實現(xiàn)繼承聯(lián)系起來:
         如前所述,聲明一個純虛函數(shù)(pure virtual)的目的是為了讓派生類只繼承函數(shù)接口,也就是上面說的接口繼承。
        純虛函數(shù)一般是在不方便具體實現(xiàn)此函數(shù)的情況下使用。也就是說基類無法為繼承類規(guī)定一個統(tǒng)一的缺省操作,但繼承類又必須含有這個函數(shù)接口,并對其分別實現(xiàn)。但是,在C++中,我們是可以為純虛函數(shù)提供定義的,只不過這種定義對繼承類來說沒有特定的意義。因為繼承類仍然要根據(jù)各自需要實現(xiàn)函數(shù)。
        通俗說,純虛函數(shù)就是要求其繼承類必須含有該函數(shù)接口,并對其進行實現(xiàn)。是對繼承類的一種接口實現(xiàn)要求,但并不提供缺省操作,各個繼承類必須分別實現(xiàn)自己的操作。
        聲明非純虛函數(shù)(impure virtual)的目的是讓繼承類繼承該函數(shù)的接口和缺省實現(xiàn)。
        與純虛函數(shù)唯一的不同就是其為繼承類提供了缺省操作,繼承類可以不實現(xiàn)自己的操作而采用基類提供的默認操作。
        聲明非虛函數(shù)(non-virtual)的目的是為了令繼承類繼承函數(shù)接口及一份強制性實現(xiàn)。
        相對于虛函數(shù)來說,非虛函數(shù)對繼承類要求的更為嚴(yán)格,繼承類不僅要繼承函數(shù)接口,而且也要繼承函數(shù)實現(xiàn)。也就是為繼承類定義了一種行為。
 總結(jié)
        純虛函數(shù):要求繼承類必須含有某個接口,并對接口函數(shù)實現(xiàn)。
        虛函數(shù):繼承類必須含有某個接口,可以自己實現(xiàn),也可以不實現(xiàn),而采用基類定義的缺省實現(xiàn)。
        非虛函數(shù):繼承類必須含有某個接口,必須使用基類的實現(xiàn)。
         一個C++類有著兩個重要的方面:用于描述行為的公共接口,以及行為的私有實現(xiàn)。
       大多數(shù)的繼承都是公有繼承:派生類繼承了基類的接口和實現(xiàn)。不過,我們也可以進行有選擇的繼承,即派生類可以只繼承接口或?qū)崿F(xiàn)。私有基類,只繼承實實現(xiàn),沒有接口;公有繼承基類,繼承接口,但繼承的實現(xiàn)可能是不完整的或不存在的(純虛函數(shù))。
 例:
我們可以用函數(shù):
 Triangle t;
 t.area();
我們只是使用了其接口,但具體的實現(xiàn)可以不知道。void area() {......}

posted @ 2009-11-21 20:20 峰 閱讀(1666) | 評論 (0)編輯 收藏

繼承簡介

    通過繼承機制,可以利用已有的數(shù)據(jù)類型來定義新的數(shù)據(jù)類型。所定義的新的數(shù)據(jù)類型不僅擁有新定義的成員,而且還同時擁有舊的成員。我們稱已存在的用來派生新類的類為基類,又稱為父類。由已存在的類派生出的新類稱為派生類,又稱為子類。
    在C++語言中,一個派生類可以從一個基類派生,也可以從多個基類派生。從一個基類派生的繼承稱為單繼承;從多個基類派生的繼承稱為多繼承。
例:

#include <iostream.h>
class Metal
{
public:
 unsigned atomicNumber;
 float atomicWeight;
 float pricePerounce;
public:
 Metal( unsigned Number=0,
         float Weight=0.000000,
         float Perounce=0.000000)
 {
 atomicNumber=Number;
 atomicWeight=Weight;
 pricePerounce=Perounce;
 }
 ~Metal() {}
    unsigned GetNumber(void) {return atomicNumber;}  //內(nèi)聯(lián)函數(shù)
    float GetWeight(void) {return atomicWeight;}
    float Getprice(void) {return pricePerounce;}
 virtual void output()
 {
  cout << "The atomic weight =" << atomicWeight << endl;
  cout << "The atomic number =" << atomicNumber << endl;
  cout << "Price per ounce =" << pricePerounce << endl;
 }
};

class Pb : public Metal  //公有繼承,單繼承
{
public:
 Pb (unsigned Number=82,float Weight=207,float Perounce=0.01):Metal(Number,Weight,Perounce) {}
 //子類構(gòu)造首先調(diào)用基類構(gòu)造函數(shù)
};

class Au : public Metal
{
public:
 Au (unsigned Number=79,float Weight=196.9665,float Perounce=450.75):Metal(Number,Weight,Perounce) {}
 Au (Pb& lemp)  //拷貝函數(shù)
 {
       atomicNumber=lemp.GetNumber()-3;
       atomicWeight=lemp.GetWeight()-10.2335;
       pricePerounce=lemp.Getprice()+450.74;
 }
};

void main ()
{
    Pb m;
 Au n=m;     //拷貝
 n.output();
}

注:

  派生類的三種繼承方式:公有繼承(public)、私有繼承(private)、保護繼承(protected)是常用的三種繼承方式:
        公有繼承時,水平訪問和垂直訪問對基類中的公有成員不受限制;
        私有繼承時,水平訪問和垂直訪問對基類中的公有成員也不能訪問;
        保護繼承時,對于垂直訪問同于公有繼承,對于水平訪問同于私有繼承。
        對于基類中的私有成員,只能被基類中的成員函數(shù)和友元函數(shù)所訪問,不能被其他的函數(shù)訪問。
        如果通過公有繼承來產(chǎn)生基類,那么這個派生類應(yīng)該是其基類的特化。
        如果派生類之間的區(qū)別在于屬性,則用數(shù)據(jù)成員來表示;如果在于行為,則用虛函數(shù)來表示。

   任何一個類都可以派生出一個新類,派生類也可以再派生出新類。

 

posted @ 2009-11-21 10:58 峰 閱讀(316) | 評論 (0)編輯 收藏

2009年11月19日

如何設(shè)置按鈕控件點擊彈出新菜單欄

函數(shù)介紹:CButtonST應(yīng)用
DWORD CButtonST::SetMenu(UINT nMenu, HWND hParentWnd, BOOL bRepaint)
{
 
HINSTANCE hInstResource = NULL;

 // Destroy any previous menu
 if (m_hMenu)
 {
         ::DestroyMenu(m_hMenu);
         m_hMenu = NULL;
         m_hParentWndMenu = NULL;
         m_bMenuDisplayed = FALSE;
 } // if

 // Load menu
 if (nMenu)
 {
  // Find correct resource handle
  hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nMenu), RT_MENU);
  // Load menu resource
  m_hMenu = ::LoadMenu(hInstResource, MAKEINTRESOURCE(nMenu));
  m_hParentWndMenu = hParentWnd;
  // If something wrong
  if (m_hMenu == NULL) return BTNST_INVALIDRESOURCE;
 } // if

 // Repaint the button
     if (bRepaint)  Invalidate();

     return BTNST_OK;
} // End of SetMenu

DWORD CButtonST::SetMenu(UINT nMenu, HWND hParentWnd, BOOL bWinXPStyle, UINT nToolbarID, CSize sizeToolbarIcon, COLORREF crToolbarBk, BOOL bRepaint)    //除前兩個參數(shù),其他參數(shù)都有初始值
{
 BOOL bRetValue = FALSE;

 // Destroy any previous menu
 if (m_menuPopup.m_hMenu)
 {
    m_menuPopup.DestroyMenu();
    m_hParentWndMenu = NULL;
    m_bMenuDisplayed = FALSE;
 } // if

 // Load menu
 if (nMenu)
 {
     m_menuPopup.SetMenuDrawMode(bWinXPStyle);
  // Load menu
     bRetValue = m_menuPopup.LoadMenu(nMenu);
  // If something wrong
  if (bRetValue == FALSE) return BTNST_INVALIDRESOURCE;

  // Load toolbar
  if (nToolbarID)
  {
   m_menuPopup.SetBitmapBackground(crToolbarBk);
   m_menuPopup.SetIconSize(sizeToolbarIcon.cx, sizeToolbarIcon.cy);

   bRetValue = m_menuPopup.LoadToolbar(nToolbarID);
   // If something wrong
   if (bRetValue == FALSE)
   {
    m_menuPopup.DestroyMenu();
    return BTNST_INVALIDRESOURCE;
   } // if
  } // if

  m_hParentWndMenu = hParentWnd;
 } // if

 // Repaint the button
 if (bRepaint) Invalidate();

 return BTNST_OK;
} // End of SetMenu

通過#ifdef BTNST_USE_BCMENU  來判斷選擇哪個函數(shù)。

程序過程:
   頭文件:
CButtonST m_btnHelp;
   源文件:
1)在當(dāng)前對話類的初始化函數(shù)中添加:
OnInitDialog()
 m_btnHelp.SetIcon(IDI_HELP, (int)BTNST_AUTO_GRAY);           //設(shè)置圖標(biāo),未點擊時變灰
 m_btnHelp.SetTooltipText(_T("Help"));                                             //輸出文字
#ifdef BTNST_USE_BCMENU
 m_btnHelp.SetMenu(IDR_MENU, m_hWnd);                                  //點擊時彈出菜單欄
#else
 m_btnHelp.SetMenu(IDR_MENU, m_hWnd);
#endif
2)設(shè)置控件交換信息:
DoDataExchange(CDataExchange* pDX)函數(shù)中
 DDX_Control(pDX,IDC_BUTTON1,m_btnHelp);  //輸出
3)新菜單欄響應(yīng)函數(shù):
新建一菜單欄:IDR_MENUNEW,設(shè)置為POP-UP;
設(shè)置子菜單:IDR_ITEM1.點擊ClassWizard,選擇當(dāng)前文檔類點擊ON_COMMAND設(shè)置響應(yīng)函數(shù)。

posted @ 2009-11-19 14:03 峰 閱讀(793) | 評論 (0)編輯 收藏

僅列出標(biāo)題  下一頁

導(dǎo)航

統(tǒng)計

常用鏈接

留言簿

隨筆檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品99久久久久久白浆小说| 欧美成人综合在线| 国产精品美女久久久浪潮软件| 极品尤物av久久免费看| 久久se精品一区二区| 亚洲一区二区四区| 国产欧美精品日韩| 久久久久久亚洲综合影院红桃| 欧美尤物一区| av成人福利| 久久国产精彩视频| 亚洲精品一区二区三区蜜桃久| 性欧美xxxx视频在线观看| 欧美日韩黄色一区二区| 欧美日韩国产色站一区二区三区| 欧美国产一区在线| 亚洲国产人成综合网站| 99精品视频一区| 亚洲欧美bt| 欧美大片在线影院| 国产欧美日韩精品丝袜高跟鞋| 国产精品国产自产拍高清av王其| 欧美午夜欧美| 国内伊人久久久久久网站视频| 国产欧美日韩视频| 亚洲国产电影| 欧美电影资源| 小处雏高清一区二区三区 | 亚洲系列中文字幕| 欧美a级片一区| 欧美日韩一区二区三区在线看| 欧美大尺度在线| 亚洲二区视频在线| 欧美国产日韩免费| 篠田优中文在线播放第一区| 国产日韩精品一区二区浪潮av| 午夜欧美精品| 美女性感视频久久久| 亚洲激情自拍| 亚洲精品久久久久久久久| 欧美大片免费观看| 久久婷婷国产麻豆91天堂| 久久躁狠狠躁夜夜爽| 亚洲一区综合| 久久综合色播五月| 亚洲欧美一区二区精品久久久| 老司机精品视频网站| 在线亚洲电影| 男人插女人欧美| 亚洲作爱视频| 欧美日本一区| 欧美成人免费在线| 精品电影一区| 欧美二区在线观看| 日韩一级大片| 久久免费精品视频| 亚洲美女啪啪| 在线观看成人av| 中文精品视频一区二区在线观看| 亚洲日本中文字幕区| 久久久久久久精| 欧美成熟视频| 亚洲国产一二三| 18成人免费观看视频| 亚洲性视频网址| 午夜久久久久久| 欧美日韩在线一区| 国产日韩欧美在线播放不卡| 亚洲黄色在线看| 亚洲视频在线看| 欧美视频在线一区二区三区| 亚洲精品久久视频| 一区二区不卡在线视频 午夜欧美不卡'| 亚洲欧洲在线一区| 国产精品一区二区久激情瑜伽| 一区二区成人精品| 久久精品国产亚洲一区二区| 精品成人国产在线观看男人呻吟| 久久国产精品久久久| 久久综合网络一区二区| 亚洲国产欧洲综合997久久| 欧美电影专区| 欧美一区二区日韩一区二区| 亚洲第一主播视频| 欧美在线影院| 一级日韩一区在线观看| 国产亚洲一区二区三区| 欧美欧美天天天天操| 久久亚洲春色中文字幕| 亚洲小视频在线| 亚洲人成人一区二区三区| 久久久久国产一区二区| 亚洲综合日本| 亚洲国产欧美另类丝袜| 黄色一区二区三区四区| 国产欧美午夜| 国产精品大片免费观看| 欧美精品不卡| 噜噜噜躁狠狠躁狠狠精品视频 | 亚洲女优在线| 久久国产视频网站| 麻豆91精品| 亚洲精品老司机| 亚洲激情网站| 午夜精品一区二区三区在线| 老司机成人网| av成人免费在线| 噜噜噜躁狠狠躁狠狠精品视频| 欧美xx视频| 黄色国产精品| 艳妇臀荡乳欲伦亚洲一区| 久久久噜噜噜久久| 91久久久精品| 亚洲欧美第一页| 免费在线播放第一区高清av| 国产精品久久福利| 136国产福利精品导航| 久久国产福利| 亚洲欧美一区二区三区极速播放| 欧美理论在线| 亚洲激情一区| 91久久久亚洲精品| 快射av在线播放一区| 国产一区二区剧情av在线| 亚洲永久在线| 一区二区三区精密机械公司| 欧美日韩国产成人在线免费 | 亚洲欧美日韩精品综合在线观看| 欧美成人黑人xx视频免费观看| 黑人巨大精品欧美一区二区| 亚洲欧美日韩在线不卡| 亚洲国产精品久久久久| 欧美国产欧美综合| 亚洲免费成人av| 亚洲国产精品福利| 免费高清在线视频一区·| 美女在线一区二区| 一二三区精品| 久久精品国产久精国产爱| 国产一区二区三区免费观看| 午夜国产精品视频免费体验区| 一本大道久久精品懂色aⅴ| 欧美日韩国产精品一区| 一区二区三区不卡视频在线观看| 亚洲国产小视频| 一本色道久久综合狠狠躁的推荐| 国产精品久久久久天堂| 久久视频精品在线| 欧美日韩国产色站一区二区三区| 午夜亚洲福利在线老司机| 久久久激情视频| 亚洲欧美卡通另类91av| 美女脱光内衣内裤视频久久影院 | 欧美在线欧美在线| 亚洲毛片av| 久久国产毛片| 欧美亚洲一区二区三区| 欧美高清在线一区| 久久夜色精品国产| 欧美人妖在线观看| 亚洲国产另类久久精品| 国产亚洲精品bt天堂精选| 99热免费精品在线观看| 日韩视频一区二区三区在线播放| 羞羞漫画18久久大片| 亚洲伊人久久综合| 国产精品国色综合久久| 亚洲午夜免费视频| 免费国产一区二区| 欧美国产激情二区三区| 久久精品视频免费观看| 欧美精品一区二| 亚洲欧美一区二区原创| 久久综合伊人77777尤物| 午夜精品久久久久影视| 久久精品欧美日韩精品| 中文在线一区| 免费日韩视频| 久久夜色精品国产亚洲aⅴ| 欧美激情视频一区二区三区免费 | 久久一区二区三区四区| 国产精品99久久久久久www| 欧美大尺度在线观看| 国产精品日韩欧美一区二区三区| 亚洲毛片在线| 亚洲视频播放| 欧美日韩精品免费看| 亚洲人体影院| 最新日韩在线| 玖玖综合伊人| 亚洲三级影院| 午夜久久久久久久久久一区二区| 欧美日韩精品是欧美日韩精品| 亚洲福利专区| 亚洲欧美制服另类日韩| 欧美视频在线视频| 亚洲欧美大片| 欧美黄色网络| 日韩午夜av电影| 国产精品理论片|