On the way

Even when I wasn't sure where I was going, I was always in a hurry.

  博客园 :: 首页 :: 联系 :: 订阅 订阅 :: 管理
  18 Posts :: 0 Stories :: 11 Comments :: 0 Trackbacks

公告

昵称:On the way
园龄:5年11个月
粉丝:1
关注:0

搜索

 
 

常用链接

最新评论

阅读排行榜

评论排行榜

推荐排行榜

2011年11月17日 #

MainFrame: 主框架类

Dlg 是Dialog 的缩写,表示对话框本身

 
App类就是这个SDI作为"程序"的入口,有点像c的Main函数,它不是从CWND中派生出来的。App表示应用程序本身。

 
View表示视图类,负责显示数据,提供编辑数据、修改数据的功能。它是指编辑区里面的事就是那块白色的中间区域,负责绘制和响应一些消息

 
Doc表示文档类,提供对数据的保存和加载。有点像数据库,保存着编辑数据,用于view的Redraw的时候用,还有保存文件。

 一般动态的编辑数据都放在Doc里面。他也不是从CWND中派生出来的,没有继承MessageBox函数,可以用AfxMessageBox函数。

 

 

1)   View中获得Doc指针    

  2)   App中获得MainFrame指针    

  3)   View中获得MainFrame指针    

  4)   获得View(已建立)指针    

  5)   获得当前文档指针    

  6)   获得状态栏与工具栏指针    

  7)   获得状态栏与工具栏变量    

  8)   Mainframe获得菜单指针    

  9)   在任何类中获得应用程序类    

  10)   从文档类取得视图类的指针(1)    

  11)   App中获得文档模板指针    

  12)   从文档模板获得文档类指针    

  13)   在文档类中获得文档模板指针    

  14)   从文档类取得视图类的指针(2)    

  15)   从一个视图类取得另一视图类的指针    

     

  VC中编程对于刚刚开始学习的同学,最大的障碍和问题就是消息机制和指针获取与操作。其实这些内容基本上是每本VC学习工具书上必讲的内容,而且通过MSDN很多问题都能解决。下面文字主要是个人在编程中指针使用的一些体会,说的不当的地方请指正。一般我们使用的框架是VC提供的Wizard生成的MFC App Wizard(exe)框架,无论是多文档还是单文档,都存在指针获取和操作问题。下面这节内容主要是一般的框架,然后再讲多线程中的指针使用。使用到的类需要包含响应的头文件。首先一般获得本类(视,文档,对话框都支持)实例指针this,用this的目的,主要可以通过类中的函数向其他类或者函数中发指针,以便于在非本类中操作和使用本类中的功能。 

    1   View中获得Doc指针    

CYouSDIDoc   *pDoc=GetDocument();一个视只能有一个文档。    

    2)   App中获得MainFrame指针    

  CWinApp   中的   m_pMainWnd变量就是MainFrame的指针    

  也可以:   CMainFrame   *pMain   =(CMainFrame   *)AfxGetMainWnd(); 

    3)   View中获得MainFrame指针 

  CMainFrame   *pMain=(CmaimFrame   *)AfxGetApp()‐>m_pMainWnd; 

    4)   获得View(已建立)指针 

  CMainFrame   *pMain=(CmaimFrame   *)AfxGetApp()‐>m_pMainWnd;    

  CyouView   *pView=(CyouView   *)pMain‐>GetActiveView(); 

    5)   获得当前文档指针 

  CDocument   *   pCurrentDoc   =(CFrameWnd   *)m_pMainWnd‐>GetActiveDocument(); 

    6)   获得状态栏与工具栏指针 

  CStatusBar   *   pStatusBar(CStatusBar   *)AfxGetMainWnd()‐>GetDescendantWindow(AFX_IDW_STATUS_BAR);    

  CToolBar   *   pToolBar=(CtoolBar   *)AfxGetMainWnd()‐>GetDescendantWindow(AFX_IDW_TOOLBAR);    

    7)   如果框架中加入工具栏和状态栏变量还可以这样      

  (CMainFrame   *)GetParent()‐>m_wndToolBar;    

  (CMainFrame   *)GetParent()‐>m_wndStatusBar;    

    8)   Mainframe获得菜单指针 

  CMenu   *pMenu=m_pMainWnd‐>GetMenu(); 

    9)   在任何类中获得应用程序类    

  MFC全局函数AfxGetApp()获得。    

  10)   从文档类取得视图类的指针    

  我是从http://download.cqcnc.com/soft/program/article/vc/vc405.html学到的,    

  从文档获得视图类指针目的一般为了控制同一文档的多个视图的定位问题,我的体会    

  特别是文字处理CEditView当产生多个视图类时,这个功能是非常需要的。      

  CDocument类提供了两个函数用于视图类的定位:    

  GetFirstViewPosition()GetNextView()      

  virtual   POSITION   GetFirstViewPosition()   const;    

  virtual   CView*   GetNextView(POSITION&   rPosition)   const;    

     

  注意:GetNextView()括号中的参数用的是引用方式,因此执行后值可能改变。    

  GetFirstViewPosition()用于返回第一个视图位置(返回的并非视图类指针,而是一    

  POSITION类型值),GetNextView()有两个功能:返回下一个视图类的指针以及用    

  引用调用的方式来改变传入的POSITION类型参数的值。很明显,在Test程序中,只有    

  一个视图类,因此只需将这两个函数调用一次即可得到CTestView的指针如下(需定    

  义一个POSITION结构变量来辅助操作):      

  CTestView*   pTestView;    

  POSITION   pos=GetFirstViewPosition();    

  pTestView=GetNextView(pos);    

     

  这样,便可到了CTestView类的指针pTestView.执行完几句后,变量pos=NULL,因为没    

  有下一个视图类,自然也没有下一个视图类的POSITION.但是这几条语句太简单,不    

  具有太强的通用性和安全特征;当象前面说的那样,当要在多个视图为中返回某个指    

  定类的指针时,我们需要遍历所有视图类,直到找到指定类为止。判断一个类指针指    

  向的是否某个类的实例时,可用IsKindOf()成员函数时行检查,如:    

    pView‐>IsKindOf(RUNTIME_CLASS(CTestView));    

  即可检查pView所指是否是CTestView类。    

     

  有了以上基础,我们已经可以从文档类取得任何类的指针。为了方便,我们将其作    

  为一个文档类的成员函数,它有一个参数,表示要获得哪个类的指针。实现如下:      

      

  其中用了两次视图类的成员函数IsKindOf()来判断,是因为退出while循环有三种    

  可能:    

     

  1.posNULL,即已经不存在下一个视图类供操作;    

  2.pView已符合要求。    

     

  12同是满足。这是因为GetNextView()的功能是将当前视图指针改变成一个视图    

  的位置同时返回当前视图指针,因此pospView的下一个视图类的POSITION,完全    

  有可能既是pos==NULL又是pView符合需要。当所需的视图是最后一个视图是最后一    

  个视图类时就如引。因此需采用两次判断。    

  使用该函数应遵循如下格式(以取得CTestView指针为例):    

  CTestView*   pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));    

  RUNTIME_CLASS是一个宏,可以简单地理解它的作用:将类的名字转化为    

  CRuntimeClass为指针。至于强制类型转换也是为了安全特性考虑的,因为从同一个    

  基类之间的指针类型是互相兼容的。这种强制类型转换也许并不必要,但能避免一    

  些可能出现的麻烦。    

     

  3.从一个视图类取得另一视图类的指针   综合12,很容易得出视图类之间互相获得    

  指针的方法:就是用文档类作中转,先用1的方法得到文档类的指针,再用2的方法,    

  以文档类的视图定位函数取得另一个视图类。同样,可以实现成一个函数:    

  (假设要从CTestAView中取得指向其它视图类的指针)    

   这个函数和2中的GetView()相比,一是多了第一句以取得文档类指针,二是在    

  GetFirstViewPosition()GetNextView()前加上了文档类指针,以表示它们是文档    

  类成员函数。有了此函数;当要从CTestAView中取得CTestBView的指针时,只需如    

  下:CTestBView*   pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView)); 

 

posted @ 2011-11-17 16:51 On the way 阅读(254) 评论(0) 编辑

不管实在C还是C++代码中,typedef这个词都不少见,当然出现频率较高的还是在C代码中。typedef与#define有些相似,但更多的是不同,特别是在一些复杂的用法上,就完全不同了,看了网上一些C/C++的学习者的博客,其中有一篇关于typedef的总结还是很不错,由于总结的很好,我就不加修改的引用过来了,以下是引用的内容(红色部分是我自己写的内容)。

用途一:

定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:

char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,

// 和一个字符变量;

以下则可行:

typedef char* PCHAR;

PCHAR pa, pb;  

这种用法很有用,特别是char* pa, pb的定义,初学者往往认为是定义了两个字符型指针,其实不是,而用typedef char* PCHAR就不会出现这样的问题,减少了错误的发生。

用途二:
用在旧的C代码中,帮助struct。以前的代码中,声明struct新对象时,必须要带上
struct,即形式为: struct 结构名对象名,如:

struct tagPOINT1

 {
    int x;

    int y;
};

struct tagPOINT1 p1;

而在C++中,则可以直接写:结构名对象名,即:tagPOINT1 p1;

typedef struct tagPOINT
{
    int x;

    int y;
}POINT;

POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时

候,或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代

码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。

用途三:

用typedef来定义与平台无关的类型。

比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:

typedef long double REAL;

在不支持 long double 的平台二上,改为:

typedef double REAL;

在连 double 都不支持的平台三上,改为:

typedef float REAL;

也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。

标准库就广泛使用了这个技巧,比如size_t。另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。
     这个优点在我们写代码的过程中可以减少不少代码量哦!

用途四:

为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部

分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化

版。举例: 

 原声明:void (*b[10]) (void (*)());

变量名为b,先替换右边部分括号里的,pFunParam为别名一:

typedef void (*pFunParam)();

再替换左边的变量b,pFunx为别名二:

typedef void (*pFunx)(pFunParam);

原声明的最简化版:

pFunx b[10];
 
原声明:doube(*)() (*e)[9];

变量名为e,先替换左边部分,pFuny为别名一:

typedef double(*pFuny)();

再替换右边的变量e,pFunParamy为别名二

typedef pFuny (*pFunParamy)[9];

原声明的最简化版:

pFunParamy e;

理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号

就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直

到整个声明分析完。举例:

int (*func)(int *p);

首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针

;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以

func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值

类型是int。

int (*func[5])(int *);

func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明

func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符

优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数

组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。

这种用法是比较复杂的,出现的频率也不少,往往在看到这样的用法却不能理解,相信以上的解释能有所帮助。

*****以上为参考部分,以下为本人领悟部分*****

使用示例:

1.比较一:

#include <iostream>

using namespace std;

typedef int (*A) (char, char);

int ss(char a, char b)
{
    cout<<"功能1"<<endl;

    cout<<a<<endl;

    cout<<b<<endl;

    return 0;
}
 
int bb(char a, char b)
{

    cout<<"功能2"<<endl;

    cout<<b<<endl;

    cout<<a<<endl;

    return 0;

}

void main()
{

    A a;

    a = ss;

    a('a','b');

    a = bb;

    a('a', 'b');
}

2.比较二:

typedef int (A) (char, char);

void main()
{

    A *a;

    a = ss;

    a('a','b');

    a = bb;

    a('a','b');
}
 

两个程序的结果都一样:

功能1

a

b

功能2

b

a

 

*****以下是参考部分*****

参考自:http://blog.hc360.com/portal/personShowArticle.do?articleId=57527

typedef 与 #define的区别:

案例一:

通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:

typedef char *pStr1;

#define pStr2 char *;

pStr1 s1, s2;

pStr2 s3, s4;
在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们

所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一

个类型起新名字。

案例二:

下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?

typedef char * pStr;

char string[4] = "abc";

const char *p1 = string;

const pStr p2 = string;

p1++;

p2++;

  是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的

文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和

const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类

型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数

据类型为char *的变量p2为只读,因此p2++错误。虽然作者在这里已经解释得很清楚了,可我在这个地方仍然还是糊涂的,真的希望哪位高手能帮忙指点一下,特别是这一句“只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已”,难道自己定义的类型前面用const修饰后,就不能执行更改运算,而系统定义的类型却可以?

 

刚刚看到楼主写的文章,不错。最后你那个问题:
const char *p1 = string; 你可以这样理解:(const char) *p1 = string, p1是一个指针,指向const char的东西,这个东西就是string(string是一个字符数组的首地址,它的地址声明后肯定是const的,除非该数组销毁),但是p1是一个指针变量,它是可以递增的,即你看到的p1++,它可以完成从数组的来遍历数组的目的。

而const pStr p2 = string;是这样的:由于p2不是指针,const直接修饰到了p2,即现在的p2是常量了,它的类型是pStr(我们自己定义的类型),相当于const int p2, const long p2等等,const都是直接修饰p2的,只不过int,long是系统类型,而pStr是我们定义的类型。为什么会出现这种效果了,就是因为typedef,它把char *定义成一个复合的类型,要从整体上来理解语义,而不是字符替换后来理解语义。

http://www.cnblogs.com/csyisong/archive/2009/01/09/1372363.html

posted @ 2011-11-17 10:39 On the way 阅读(6) 评论(0) 编辑