引用:http://blog.sina.com.cn/s/blog_4c0cb1c001014kmj.html
微软基础类库MFC(Microsoft Foundation Classes),是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows的API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。
初学者常误认为VC++开发必须使用MFC。这种想法是错误的。作为Application Framework,MFC的使用只能提高某些情况下的开发效率,只起到辅助作用,而不能替代整个Win32 程序设计。
Application Framework
基本上你可以说,Application Framework是一个完整的程序模型,具备标准应用软件所需的一切基本功能,像是文件存取、打印预视、资料交换...,以及这些功能的使用接口(工具栏、状态列、菜单、对话框)。
Windows 应用程序中,MFC 的主包含文件为"Afxwin.h"。
MFC实际上是微软提供的,用于在C++环境下编写应用程序的一个框架和引擎,VC++是Windows下开发人员使用的专业C++ SDK(专业软件开发平台)(SDK,Standard SoftWare Develop Kit),MFC就是挂在它之上的一个辅助软件开发包,MFC作为与VC++血肉相连的部分(注意C++和VC++的区别:C++是一种程序设计语言,是一种大家都承认的软件编制的通用规范,而VC++只是一个编译器,或者说是一种编译器+源程序编辑器的IDE
MFC是Win API与C++的结合,API,即微软提供的Windows下应用程序的编程语言接口,是一种软件编程的规范,但不是一种程序开发语言本身,可以允许用户使用各种各样的第三方(如我是一方,微软是一方,Borland就是第三方)的编程语言来进行对Windows下应用程序的开发,使这些被开发出来的应用程序能在Windows下运行,比如VB,VC++,Java,Delhpi编程语言函数本质上全部源于API
最后要明白MFC不只是一个功能单纯的界面开发系统,它提供的类绝大部分用来进行界面开发,关联一个窗口的动作,但它提供的类中有好多类不与一个窗口关联,即类的作用不是一个界面类,不实现对一个窗口对象的控制(如创建,销毁),而是一些在Windows(用MFC编写的程序绝大部分都在Windows中运行)中实现内部处理的类,如数据库的管理类等,学习中最应花费时间的是消息和设备环境,对C++和MFC的学习中最难的部分是指针,C++面向对象程序设计的其它部分,如数据类型,流程控制都不难,建议学习数据结构C++版。
MFC是面向对象程序设计与Application framework的完美结合,他将传统的API进行了分类封装,并且为你创建了程序的一般框架
2012.6
C++ 类和类的定义
类:
它是将不同类型的数据和与这些数据相关的操作封装在一起的集合体。(参数和函数)
这有点像C语言中的结构,唯一不同的就是结构没有定义所说的“数据相关的操作”,“数据相关的操作”就是我们平常经常看到的“方法”。
类的定义格式 (和结构体类似)
class <类名>
{
public:
<成员函数或数据成员的说明>
private:
<数据成员或成员函数的说明>
};
<各个成员函数的实现>
下面给出一个日期类定义的例子:
class TDate
{
public:
void SetDate(int y, int m, int d);
int IsLeapYear();
void Print();
private:
int year, month, day;
};
//类的实现部分
void TDate::SetDate(int y, int m, int d)
{
year = y;
month = m;
day = d;
}
int TDate::IsLeapYear()
{
return(year%4==0 && year0!=0) || (year@0==0);
}
void TDate::Print();
{
cout<
}
这里出现的作用域运算符::是用来标识某个成员函数是属于哪个类的。
该类的定义还可以如下所示:
class TDate
{
public:
void SetDate(int y, int m, int d)
{year=y; month=m; day=d;}
int IsLeapYear()
{return(year%4==0 && year0!=0) || (year@0==0);}
void Print()
{cout<
private:
int yeay, month, day;
}
这样对成员函数的实现(即函数的定义)都写在了类体内,因此类的实现部分被省略了。如果成员函数定义在类体外,则在函数头的前面要加上该函数所属类的标识,这时使用作用域运算符::。(和结构体类似)
4、经常习惯地将类定义的说明部分或者整个定义部分(包含实现部分)放到一个头文件中。
在类的声明和成员函数的实现(即函数的定义)分开写时,在类的声明部分中,不用写出变量名,只要声明参数的类型即可.
通常将成员函数写在前面,数据成员写在后面.
原文:http://hi.baidu.com/zhengfujun/blog/item/7586a1dc59df5cd18d102923.html
析构函数 ~stud( )
如果构造函数打开了一个文件,最后不需要使用时文件就要被关闭。析构函数允许类自动完成类似清理工作,不必调用其他成员函数。
析构函数也是特殊的类成员函数。简单来说,析构函数与构造函数的作用正好相反,它用来完成对象被删除前的一些清理工作,也就是专门的扫尾工作。
当你用“new”操作符为变量或指针动态分配内存时,它们所占用的内存不会随着你的程序的关闭而关闭,这时就需要用到析构函数来把你的变量或指针销毁,以腾出它们所占用的内存空间~~~~
以C++语言为例,析构函数名也应与类名相同,只是在函数名前面加一个波浪符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数,它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。
也就是说在包含该对象的函数的末尾就会调用析构函数
局部的对象 在该对象声明的函数末尾被释放...
你可以看下作用域的定义..析构函数就是在对象的作用域的末尾释放
为了不误导人...我还是举个例子..
如果是
class A
{
....
}
void f()
{
A a;
//这种情况a的作用域就是整个函数 在f末尾释放
}
void f()
{
for(A a;a.yes();a++)//这里声明的是一个计数器a..(这种情况一般是迭代器)..
{
...
}
//这里是a作用域结束的时候 调用析构函数
}
void f()
{
A* p=new A;
delete p;//A作用域结束 调用析构
}
如果A是全局对象..那么就在程序末尾释放
显式的调用很少见..我就不举例了..
VC
1、C++中 "cannot open Debug/*.exe for writing"
第一次编译运行后,你没有关掉那个程序,所以更改后再次编译就提示不能写入。
记得编译前关闭程序,或者到任务管理器的看看进程是否存在,有的话结束掉。
那么打开任务管理器看看那个进程在不在,可能你关了窗口,但程序还没有结束
2012.7.22
cout<<"Hello,World!"<<"Flush the screen now!!!"<<flush;
这样当程序执行到operator<<(flush)之前,有可能前面的字符串数据还在缓冲区中而不是显示在屏幕上,但执行operator<<(flush)之后,程序会强制把缓冲区的数据全部搬运到输出设备并将其清空。而操纵符endl相当于<<"\n"<<flush; ( 换行,刷新缓冲)
2012.8.14
GDI
GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。
pDC指向的是你从堆上申请的内存块
也就是GDI对象.就是常说的设备上下文.他其实是个结构体
用来保存需要处理的对象的一些属性
pDC看你的声明是怎么处理的
有时候在函数中当参数,接受的是你的参数的地址
有时候你需要绘图的时候用
CDC *pDC;
pDC=new CDC;
或者pDC->CreateCompatibleDC();
或者pDC->m_hDC=::GetDC();
等..
他本身就是一个CDC对象
他包含一个HDC的对象!也就是CDC的核心
DC是MFC的DC的一个类
HDC是DC的句柄,API中的一个类似指针的数据类型.
MFC类的前缀都是C开头的
H开头的大多数是句柄
这是为了助记,是编程读\写代码的好的习惯.
CDC中所有MFC的DC的基类.常用的CClientDC dc(this);就是CDC的子类(或称派生类).
CDC等设备上下分类,都含有一个类的成员变量:m_nHdc;即HDC类型的句柄.
记住下面的一句话,会有助于你的理解.
MFC的类,是在用window API语句开发出来的有一定功能的小程序.(也可称为类).使用它的默认方法,就是,记住它的名字与参数(可以用笔记,代替脑记).
如果将window api比做汇编语言
那么MFC就相当于Basic语言.
2012.8.24 基类私有成员的访问权
C++ 基类私有成员被子类继承吗2011-6-9 15:23提问者: 623669584 | 浏览次数:1031次
C++ 基类私有成员被子类继承吗,子类继承了基类的私有成员 但不能被访问吗?
还 是 不能继承基类的私有成员 也不能访问基类的私有成员???
我来帮他解答
2011-6-9 15:42满意回答
你好,总的来说,基类的所有成员被派生类继承后都变成派生类所拥有了,只是对于继承而来的private成员没办法直接访问而已,这样设计保证了基类private成员的安全性。如果你希望基类的某些成员被派生类继承且能访问而又不允许外界普通用户代码访问的话,将基类的那些成员声明为protected就好了。
C++ Primer里面关于访问控制和继承是这么说的
“
在基类中,
public和private标号
具有普通含义:用户代码可以访问类的public成员而不能访问private成员,private成员只能由基类的成员和友元访问。
派生类对基类的public和private成员的访问权限于程序中任意其他部分一样:它可以访问public成员而不能访问private成员。
protected标号
可以被派生类对象访问但是不能被该类型的普通用户访问。
”
顺便提一下,对于protected成员还蛮特别的:“派生类只能通过派生类对象访问其基类的protected成员,派生类对其基类类型对象的protected成员没有特殊访问权限”
2012.8.24
消息函数OnLButtonDown和OnLButtonUp中最后一句CView::OnLButtonDown(nFlags, point)的作用
暂且可信的回复:
如果你注释了CView::OnLButtonDown(nFlags, point); 后果就是当有WM_LBUTTONDOWN消息的时候它只会执行MessageBox("View Clicked!"); 而系统一些默认下的LBUTTONDOWN操作不会被执行,如果你了解switch语句的话,应该知道它有个default,CView::OnLButtonDown(nFlags, point);和default性质一样,它把你处理过的WM_LBUTTONDOWN消息传递给那些还能处理这样消息的处理函数
http://zhidao.baidu.com/question/393611846.html
其他回复:
CDrawDemoView类是从CView继承类,在CView的派生类CDrawDemoView中使用过(UINT nFlags, CPoint point)等参数后,系统要将他们返回基类,如果你改变参数的内容 基类将无法得到这些参数,对这个函数没影响是由于你没调用他的基类函数,如果你调用基类函数并且使用这两个返回的参数,就有可能错误。所以这个函数尽量不要改变参数的值,但是可以使用.
http://zhidao.baidu.com/question/109794460
CView中原本就实现了鼠标左键处理功能:OnLButtonDown
而CMyView继承自CView,从而CMyView即使不覆盖定义
OnLButtonDown函数,也可以直接使用CView的OnLButtonDown函数。
CMyView之所以覆盖定义(override) OnLButtonDown函数,是因为继承来
的版本功能不满足要求。
CMyView类在重新实现OnLButtonDown函数时发现,只要先做一些预
处理(以下几行就是预处理),
CMyDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->m_pointMouse=point;
Invalidate();
后面就完全可以按照原来的方式处理了,所以直接调用基类
的OnLButtonDown函数版本:
CView::OnLButtonDown(nFlags,point);
注意类名前缀,而不是:
OnLButtonDown(nFlags,point);
//这个将调用CMyView::OnLButtonDown(nFlags,point);
//这变成了递归调用,递归若没有退出条件将导致堆栈溢出错误
http://tieba.baidu.com/f?kz=293822983
有趣的答复:
说白了就是把消息传回去给老总,简单分析说明就是有一个客户想要告诉你们公司一个消息,但这个消息先让你知道了,你可以在把消息传达到老总那时之前做一些手脚,做成手脚之后再把消息传给老总。你所说的最后那行代码就是传回给老总的意思。
http://www.vczx.com/forum/showthread.php?s=799ee5a93656a30d81f6962be6beab0b&threadid=15033
DoDataExchange() 2012.8.24
引自:http://blog.sina.com.cn/s/blog_69ebf25c0100mra6.html
我不清楚,但好像这个引用解释的不错:http://k.pconline.com.cn/question/1686411.html
对话框的构造函数里面初始化一个变量,再用DoDataExchange函数将它绑定到你的动态按扭中,比如:
DDX_Check(pDX, IDC_CHECK1, m_Lesson1);这就是将m_Lesson1(这是一个外部变量,其定义在对话框的构造函数里)绑定到IDC_CHECK1中。
看下DDX_Check函数原型:void AFXAPI DDX_Check(CDataExchange* pDX, int nIDC, int& value);可以看到m_Lesson并不是真的添加到IDC_CHECK1控件里了,注意这是int& value,只是一个值引用而已。差不多的意思就是这个变量被框架传递给控
DoDataExchange永远不被直接调用,它只是呼叫UpdateData函数时才会被调用。(因为每更新一次,它都需要重新绑定一次。是这样子吗?)
UpdataData函数内部调用了DoDataExchange。该函数只有一个布尔型参数,它决定了数据传送的方向。
UpdateData(false)是将变量的值传到控件.
UpdateData(TRUE)是从控件中取值到关联的变量
网友评论不错:http://www.cnblogs.com/flyingfish/archive/2007/03/21/682274.html
void CDlgSelectCS::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_SCR, m_ScrCS_Name);
DDX_Text(pDX, IDC_EDIT_DEST, m_DestCS_Nam);
}
DoDataExchange会被框架调用,用来改变和验证对话框的数据。在这个函数中一般是将控件和某些变量关联,当在其它地方改变量的值,通过UpdateData 进行双向交换。如:
UpdateData();//将控件的值传给变量
m_ScrCS_Name = "Xian 1980.prj";//分别为控件的变量赋值
UpateData(FALSE);//将变量的值传给控件
VS利用向导添加数组 2012.8.27
添加数组:
类型自己写 如创建8个元素的数组:float [8]
名字是:angle
添加指针数组:
类型自己写 如创建8个元素的数组:float * [8]
名字是:angle
控件变量 添加变量 2012.8.27
MFC中关联一个控件和变量的时候,可以选择是控件方式还是值方式,如果是控件方式,那么就是这个变量就代表了控件,如果是值方式,那么这个变量就代表了控件中显示的值。比如你说的静态控件,可以与CStatic类型的变量关联,也可以与CString类型的关联。其实所谓的关联,只是MFC的一层封装而已,内部还是采用Windows SDK来操作的。你如果想深入了解的话,可以去看看Windows SDK开发方面的东西,或者也可以深入到MFC的源代码中看看,MFC源代码在安装时有选项。
消息映射机制 消息映射表 2012.8.29
BEGIN_MESSAGE_MAP(CCH372_CPlusDlg, CDialog)
这样就是一个工程叫CCH372_CPlusDlg的消息映射表,它以BEGIN_MESSAGE_MAP开始
http://baike.baidu.com/view/3517678.htm
2012.9.1 CWnd CDC
CWnd 是窗口类
CDC 是设备描述类
CWnd 是封装了所有对窗口操作的类
CDC 是封装了所有对绘图操作的类
CWnd 封装了一系列窗口的操作的API,如窗口移动,窗口创建销毁显示,子父窗口关联等等
CDC 则是绘图用的,如绘个线了,绘个矩形了,绘个其它字体了,绘个Bitmap了什么的
2012.9.5 显示最近打开文件 LoadStdProfileSettings();
最近文件列表可以让你很方便地打开你以前曾经打开过的文件,那么,如何为自己的应用程序加入最近文件列表功能呢?最简单的方法就是在你新建工程的时候选择包含最近文件列表功能,也就是在 MFC AppWizard 的第 4 步的时候使 “How many files would you like on your recent file list?” 的值不为 0 即可。
1、显示最近文件
如果你在新建工程的时候没有选择包含最近文件列表功能,那么可以按照如下的方法为你的工程加入它:
1.在你的“文件”菜单中添加一个名称为“最近文件”的菜单项,其 ID 为 ID_FILE_MRU_FILE1。
2.在你的工程的 App 类的 InitInstance 方法中将
LoadStdProfileSettings(0);
改成:
LoadStdProfileSettings();
即可。
最近文件列表项是保存在注册表中,以你的工程名为主键的字符串值中,可以用SetRegistryKey(_T("skyice software"));改成你需要的名称:skyice software。
(
这样,你的工程就有了最近文件列表功能。事实上,以这种方法生成的最近文件列表项是保存在注册表中HKEY_CURRENT_USER\Sofrware\Loacl Appwizard-Generated Applications 下,以你的工程名为主键的, Recent File List 主键中 File? 格式的,字符串值中。LoadStdProfileSettings 的参数值决定了保存在这里的最近文件的数目,其默认值(没有参数时)为 4。 Loacl Appwizard-Generated Applications 主键是Visual C++ 默认的,在工程的 App 类的 InitInstance 方法中由 SetRegistryKey() 函数创建的,你可以将其改成你需要的名称,例如:SetRegistryKey(_T("skyice software"));
)
那么,如何处理从菜单中选择的最近文件列表中的文件呢?由于在菜单中只有 ID_FILE_MRU_FILE1 这一个菜单项,其余的菜单项都是由 LoadStdProfileSettings(); 动态的加上的,因此,用一般的方法难以实现对菜单项的响应。此时,可以采用如下的方法:
2、打开选择的文件
1.在 CMainFrame 类中加入对菜单项 ID_FILE_MRU_FILE1的响应。
2.在 MainFrm.cpp 中将
ON_COMMAND(ID_FILE_MRU_FILE1,OnFileMruFile1)
改成
ON_COMMAND_RANGE(ID_FILE_MRU_FILE1,ID_FILE_MRU_FILE4, OnFileMruFile1)
即可。
以后,所有对最近文件列表中文件的选择都由 CMainFrame 方法 OnFileMruFile1 响应,你可以在此函数中判断具体是选择了哪个文件,进而做出相应的处理。
转自:http://hi.baidu.com/haoyan1983/blog/item/01821f000bb38f1a7aec2c68.html
GetHeadPosition和GetHead
第一个得到头索引,第二个得到头元素:
1、Gets the position of the head element of this list.
POSITION GetHeadPosition( ) const;
2、Gets the head element (or a reference to the head element) of this list.
const TYPE& GetHead( ) const;
TYPE& GetHead( );
追问
没太懂,有什么区别,第一个得到的是在记录集中的位置吗
回答
是的。虽然与一般的inti索引有不同,但是可以使用++、--、+、-等操作符来获取其它元素的位置。
http://msdn.microsoft.com/en-us/library/7c6e2t3d(v=vs.80).aspx
2012.9.6
GetHeadPosition() 和GetNext()
etHeadPosition 返回的是链表头元素的位置
GetNext(pos) 返回的是连标中pos所指的元素并将pos指向下一个元素
调用GetNext后pos的值就改变了
可以用一下循环遍历链表所有元素
for (POSITION pos = list.GetHeadPosition(); pos != NULL;)
{
(yourclass*) yc = (yourclass*)GetNext(pos);
}
MSDN中:
C++
CObList list;
POSITION pos;
list.AddHead(new CAge(21));
list.AddHead(new CAge(40)); // List now contains (40, 21).
// Iterate through the list in head-to-tail order.
#ifdef _DEBUG
for (pos = list.GetHeadPosition(); pos != NULL;)
{
afxDump << list.GetNext(pos) << _T("\n");
}
#endif
The results from this program are as follows