基础太差,请教大家一个初级问题

Snow_Ice1111 2005-12-11 11:28:43
typedef LRESULT (*PFNMSG)(HWND,UINT,WPARAM,LPARAM);

如何理解这行代码的意义?
...全文
265 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
Snow_Ice1111 2005-12-14
  • 打赏
  • 举报
回复
上面的举例2中的说明和代码是我现阶段学习的目标,值得认真学习!结贴了!
Snow_Ice1111 2005-12-14
  • 打赏
  • 举报
回复
感谢大家的参与,感谢Atomictry(天影)朋友准确、耐心的解释和完全无误的测试例子!
Atomictry(天影)朋友所举的例1完美地回答了我的问题1,同时进一步说明了我的问题2的含义,特别感谢一下!我的结贴总结也省了^_^
rageliu 2005-12-13
  • 打赏
  • 举报
回复
函数指针

int (*Fun)(int,int);
如果有 int m(int a,int b);
可以 Fun = m;
通过Fun调用m函数

guosx 2005-12-13
  • 打赏
  • 举报
回复
mark
kevinlvchina 2005-12-13
  • 打赏
  • 举报
回复
楼上的兄弟和 Zark(金陵五月) 都是认真的人啊!向你们学习!
同意楼上提出的:
我希望这里多点人讨论设计模式的东西,而不是纠缠与开发环境本身,那这里大家的水平将会有很大提高。对于很多问题,我们应该用例子来解决给提问者,这样比较节省他们时间!

虽然我也刚学c++,也需要了解很多细节的东西,csdn我也是刚来,高手不少,但和我一样水平浅的人就更多了.能够参与进来让我学了不少东西,更多的是给了我学习c++的勇气 I am not alone.呵呵,
回答一下楼主提出的:

"DRAWF box;" is equivalent to the declaration "void box( int, int );"可还是不明白,可否请大家举个再具体一些的例子来说一下!

这句话就是告诉你以后在声明有两个int参数,且返回值是void参数的时候,如我需要声明:
void MyFunc(int a,int b)的时候,我就不必写这么多了,可以直接这样写嘛:DRAWF MyFunc;
因为头文件里已经有了:typedef void DRAWF( int, int );
明白了吧,不难的,呵呵!给你个建议:多看基础的书,像我们这个水平遇到的很多问题在一般技术层次的书上都能找到,还有就是加强英语学习啊,哈哈!

说了这么多,无非就是我在这发现了很多水平和我相近的朋友,处在咱这水平,遇到的问题太多了,有时对自己的选择也有过茫然.借楼主的这个帖子,我希望能认识些热爱c++能共同进步的朋友,年龄水平不限,给我留言即可,咱们一起学习,有个照应!
k

Seu_why 2005-12-13
  • 打赏
  • 举报
回复
板凳 学习 ~
Atomictry 2005-12-13
  • 打赏
  • 举报
回复
哎,Zark(金陵五月)还真较上劲了。
你说的很对,我那样说法也许误到到他了。

你知道我为什么要说不是类型,楼主的意思,这个PFNMSG是一个固定的结构,他以为是个结构体什么的东西,而兄弟你也说“PFNMSG是个函数指针,指向window的消息处理函数。”也误导他了,他更确切的认为PFNMSG是微软的一种类型。

那我这样说吧:是用户自定义的类型。

既然用到了typedef,那说明这个类型其实只是一个标志而已,你完全可以用阿猫代替,也可以用阿狗代替。typedef LRESULT (*PFCat)(HWND,UINT,WPARAM,LPARAM);和typedef LRESULT (*PFDog)(HWND,UINT,WPARAM,LPARAM);并没有区别。
定义了这个类型后,以后只要是有相同参数类型,相同返回值的函数,都可以用它来指向。
举例1:

#ifdef VC_EXTRALEAN
#pragma message("MFC")
#define OUTPUT TRACE
#else
#pragma message( "WIN32" )
#define OUTPUT printf
#endif

typedef int(*PFCatOrDog)(unsigned int);
bool TestCat(unsigned int uCatCounts)
{
OUTPUT("Cats: %d\n", uCatCounts);
return true;
}
bool TestDog(unsigned int uDogCounts)
{
OUTPUT("Dogs: %d\n", uCatCounts);
return true;
}
void main()
{
PFCatOrDog pfCatDog = TestCat; // 指向TestCat函数
pfCatDog (10);
pfCatDog = TestDog; // 指向TestDog函数
pfCatDog (20);
// 意思是,只要是TestCat, TestDog参数类型,返回值类型与PFCatOrDog一样 ,
// PFCatOrDog 都可以指向该函数地址。你也可以定义一组函数指针数组分别让它
// 们对应到不同函数
}

举例2:
MFC的框架让初学者觉得难,为什么难,类关系复杂,封装太封闭。
让使用了半年左右的人觉得爽,为什么爽,因为很多现成的类库使用。
却让用了一两年的人觉得难以驾驭,为什么难以驾御,当你的工程越来越大时,你将会发现测试它的单元太困难,所以我总是力求降低各模块间耦合程度。

以下这个程序要复杂一点,如果你熟悉回调,熟悉函数指针,小case。
这个利用的好,可以最底限度降低类之间的耦合性;当时是从C语言下学到的思想,我觉得对于MFC框架结构再好不过,现在我是这样认为,也许过了半年,可能我又可以用新的思想来对付它。-_-

你可以这样思考这个程序的用途,类B是你的MFC的主对话框类,类A是B的子对话框,A::OnOK()是按下子对话框A的OK按钮。

如果有高手有降低耦合度更好的方法也请告诉我,通过MVC的思想,用对话框继承于一个抽象基类的方法,我也已经实现。

我希望这里多点人讨论设计模式的东西,而不是纠缠与开发环境本身,那这里大家的水平将会有很大提高。对于很多问题,我们应该用例子来解决给提问者,这样比较节省他们时间!

// A.h
#ifdef VC_EXTRALEAN
#pragma message("MFC")
#define OUTPUT TRACE
#else
#pragma message( "WIN32" )
#define OUTPUT printf
#endif

#define EVENT_ONOK 0x0000

typedef struct tagModelEvent ModelEvent;
typedef struct tagModelListener ModelListener;
typedef bool (*PFNLISTENER) (void *pInterface, ModelEvent *pEvent);
struct tagModelEvent
{
unsigned int evCode;
unsigned int dwParam; // 其他信息;
};
struct tagModelListener
{
PFNLISTENER pfnListener;
void* pListenerData;
};

class A
{
public:
A() {}
virtual ~A() {}

public:
bool AddListener (PFNLISTENER pfn, void * po) // 注册监听
{
m_ModelListener.pfnListener = pfn;
m_ModelListener.pListenerData = po;
return true;
}
bool NotifyToApplet (ModelEvent *pEvent) // 通知上一级applet
{
if(!m_ModelListener.pfnListener)
return false;
if (!m_ModelListener.pfnListener(m_ModelListener.pListenerData , pEvent))
return false;
return true;
}
void OnOK()
{
ModelEvent evt;
evt.evCode = EVENT_ONOK;
evt.dwParam = NULL; // other info;
NotifyToApplet(&evt);
}

private:
ModelListener m_ModelListener;
};

// B.h
#include "A.h"

bool Listener_Handle_Applet(void *pInterface, ModelEvent *pEvent);
class B
{
public:
B()
{
a.AddListener((PFNLISTENER)Listener_Handle_Applet, this);
}
virtual ~B() { }

public:
void dosomething()
{
OUTPUT("do something\n");
}

private:
A a;
};

#include "B.h"
bool Listener_Handle_Applet(void *pInterface, ModelEvent *pEvent)
{
B *pB = (B *)pInterface;
switch (pEvent->evCode)
{
case EVENT_ONOK:
pB->dosomething();
break;
default:
break;
}
return true;
//return pB->NotifyToOtherApplet(pEvent); // 如果B不想处理,可以再传递给
//它的上一层applet
}

希望高手拍砖。 别太狠啊~
Snow_Ice1111 2005-12-12
  • 打赏
  • 举报
回复
PFNMSG又是什么数据类型?

--------------------------------------------------------------
用“PFNMSG”作关键字在MSDN搜索,找到4个有效结果,它们都是异口同声地说:所有的VS 6范例都包含在一个可下载的可执行文件中,里面用到了如下的关键字:“............; pfncmd; pfnmsg; ............”。
我觉得它应该是一个结构体,不知道对不对?
谁能告诉我它的定义是什么,有哪些数据成员?我在VC中用F12查不到丝毫它的信息,请大家帮帮忙啊!!
Snow_Ice1111 2005-12-12
  • 打赏
  • 举报
回复
看过各位的回复后,可否这样理解这行代码的意义:
typedef LRESULT (*PFNMSG)(HWND,UINT,WPARAM,LPARAM);
有了上面这行代码后,以后凡是有声明函数中的形参是(HWND,UINT,WPARAM,LPARAM),且返回值类型是LRESULT的,则它的返回值一律改为返回PFNMSG的指针。

不知道这样的理解对不对?
Snow_Ice1111 2005-12-12
  • 打赏
  • 举报
回复
这问题好象比我想象的有难度,再加80分,请大家多多讨论。楼上Zark(金陵五月)和Atomictry(天影)朋友各25分先记下了,谢谢你们的解释!
Jacques928 2005-12-12
  • 打赏
  • 举报
回复
HUN
Snow_Ice1111 2005-12-12
  • 打赏
  • 举报
回复
从MSDN上找来这么一段:
typedef void DRAWF( int, int );
This example provides the type DRAWF for a function returning no value and taking two int arguments. This means, for example, that the declaration

DRAWF box; //这个象是声明全局(写在外面的话)或局部变量(写在函数体内的话)
is equivalent to the declaration

void box( int, int ); //这个肯定是声明函数的原型嘛
可还是不明白,可否请大家举个再具体一些的例子来说一下!
rainliuyu 2005-12-12
  • 打赏
  • 举报
回复
PFNMSG fun; 声明一下

以后就可以这样调用一个函数fun(HWND,UINT,WPARAM,LPARAM);
当然首先得给fun付一个函数体。
zzuu 2005-12-12
  • 打赏
  • 举报
回复
我认为在隐式加载dll时用得最多,所以“一般用于dll”也不算什么错误。
Snow_Ice1111 2005-12-12
  • 打赏
  • 举报
回复
刚才在范例中试了下,楼上j805(这儿)朋友和大家的说法是对的,这个PFNMSG果然可以随便换一个名堂的,确实不是什么“希奇货”,只是不明白MS为什么要在MSDN中说这是什么keyword,搞得我险些在牛角尖里出不来了^_^
kugou123 2005-12-12
  • 打赏
  • 举报
回复
typedef LRESULT (*PFNMSG)(HWND,UINT,WPARAM,LPARAM);

这是定义一个函数指针类型。
hjcy_2002 2005-12-12
  • 打赏
  • 举报
回复
楼上的强,基本上全部正确
j805 2005-12-12
  • 打赏
  • 举报
回复
在msdn上搜到是巧合,或者说ms恰恰就是这么定义了的.

在你的问题中PFNMSG就是自己起的名字,你可以
typedef LRESULT (*MyGod)(HWND,UINT,WPARAM,LPARAM);

这样MyGod和PFNMSG是一样的.

Zark 2005-12-12
  • 打赏
  • 举报
回复
纠正一下楼上几个错误。
1。一般用于dll,回调函数。
没有必要“一般用于dll“,实际上它更常用于EXE,也不必要用于“回调函数”。

2。PFNMSG并不是一个类型,只是个函数指针名字而已
PFNMSG 是一个类型,它可以做以下声明 PFNMSG pf;

3. "char *pfoo:
那么PFNMSG就象其中的pfoo一样。"

这个举例是不当的,pfoo是变量名,char* 是类型名,PFNMSG实际上是个类型名,所以例子恰好说反了,应说“PFNMSG就象其中的char* 一样”

Snow_Ice11111 2005-12-12
  • 打赏
  • 举报
回复
谢谢楼上he_sl(he_sl)朋友的回复,这样的结果就是我最希望看到的答复,我马上写几段代码验证一下是否正确,以便我在结贴前的总结中解释一下这个问题的标准答案。

至于PFNMSG是什么数据这个问题我还是不明白,不过可以肯定一点:这决不是有的朋友认为是自己起的名字,可以随便换一个的。因为果真如此的话,MSDN上是绝对搜不到结果的(不包括巧合的情况)。

请大家继续探讨一下PFNMSG。
加载更多回复(8)

16,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧