代码之家  ›  专栏  ›  技术社区  ›  Simsons

回调函数在构建和dll时如何有用

  •  0
  • Simsons  · 技术社区  · 14 年前

    回调函数是否与C(.NET)中的事件等效?

    我对回调函数的理解是,它是一个通过引用该函数来调用的函数。

    示例代码为:

    void cbfunc()
    
    {
            printf("called");
     }
    
    int main ()
    
    {
    
        void (*callback)(void);
    
        callback=(void *)cbfunc;
    
       callback();
    
       return 0;
    

    }

    现在我不明白的是,这个用法是如何完全用于从DLL通知客户机的。

    假设我想在我的dll method2()上接收数据时执行一些method1()。

    任何与.NET中事件的比较都将在很大程度上有所帮助。

    4 回复  |  直到 8 年前
        1
  •  1
  •   skimobear    14 年前

    回调和接口类是管理代码边界的好方法。它们有助于在代码中创建正式的边界和/或层,而不是将所有内容集中在一起。在处理大型软件解决方案时,这是必要的。

    下面是一个如何使用回调和接口类的示例。在库/dll代码中,唯一应该向主可执行文件公开的是myddl ou接口类和函数getmydllinterface()。使用这样的接口类完全隐藏了主可执行文件的实现细节。接口类还允许主可执行文件用它注册一个稍后执行的函数(即回调)。

    // Begin library/dll Public Interface used by an executable
    class mydll_interface {  
    public:  
        typedef void (*callback_func_t)();  
    public:  
        virtual void do_something() = 0;  
        virtual void registerFunction( callback_func_t ) = 0;  
    };  
    
    static mydll_interface* getMyDllInterface();
    
    // End library/dll Public Interface used by an executable
    
    // Begin library/dll Private implementation
    class mydll_implementation : public mydll_interface {  
    public:  
        void do_something() {  
            printf("Hello World\n");  
            _callback_func();  
        }  
        void registerFunction( callback_func_t c) {  
            _callback_func = c;  
        }  
    private:  
        callback_func_t _callback_func;  
    };  
    
    static mydll_interface* getMyDllInterface() {  
        return new mydll_implementation();  
    };  
    // End library/dll Private implementation
    
    // Begin main executable code
    void myMainAppFunc() {  
        printf("hello World Again\n");  
    }  
    
    int main() {    
        mydll_interface* iface = getMyDllInterface();  
        iface->registerFunction(&myMainAppFunc);  
        iface->do_something();  
    };  
    // End main executable code
    
        2
  •  1
  •   Pavel Radzivilovsky    14 年前

    将指针传递给第三方例程(不必是dll),当需要通知时,克隆的指针将“回调”该指针。

    与.NET事件类似,后者也是回调类型。

    顺便说一下,DLL在C++中不如在.NET中流行。这是由于不可能共享静态变量(因此是单例变量),这一问题也被称为缺乏动态链接(在Unix系统中,这是通过共享对象解决的,共享对象是动态加载库的一个完全不同的概念)。静态库提供了更好的代码重用策略。

        3
  •  1
  •   roalz Steve Townsend    8 年前

    回调函数实现了与C中的委托类似的目的。

    例如,win32 api提供了一个定时服务,可以通过调用settimer来访问它。settimer由系统dll导出,但机制与在用户dll中使用的机制完全相同。在代码中,您可以通过执行以下操作来访问计时器:

    void 
    CALLBACK
    MyTimerCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
    {
    // do something
    }
    
    ...
    
    TIMERPROC fn = &MyTimerCallback;
    int delay = 500;  
    SetTimer(NULL,0,delay,fn); 
    

    调用settimer,并传入回调函数,允许操作系统在每次计时器计时时回调函数。当然,这里没有多播功能,特别是在settimer的情况下,回调函数必须是C函数或静态类方法。没有与函数关联的类或对象实例。

    类似的模式也可以在.NET中实现-我确信.NET有自己的计时器范式,但是有一段时间我们可以假设它实现了一个需要TimerDelegate的SetTimer函数。

    在用户代码中,在对象中,然后将myTimerProc定义为具有与委托匹配的签名的函数。像这样调用它

    TimerDelegate d = new TimerDelegate(myObject.MyTimerProc);
    SetTimer(0,0,delay,d);
    

    或者,如果“计时器”是一个与TimerDelegate匹配的事件,那么等效的C代码应该如下所示:

    timers += new TimerDelegate(myObject.MyTimerProc);
    

    注意:我的C非常生锈,因此不要将这些代码示例作为最佳实践甚至工作代码的任何一种示例:p


    在定义自己的回调函数时,始终定义回调函数以获取空隙*“上下文”参数是很好的做法,因为这允许C++程序员存储他们的“这个”指针并检索它。

    // the first parameter to the callback fn is a void* user supplied context parameter
    typedef void (CALLBACK* MyCallbackFn)(void* context, int etc);
    
    // and, the dll export function always takes a function pointer, context parameter pair.
    DLL_EXPORT void SomeExportedFn(MyCallbackFn, void* context);
    
        4
  •  -1
  •   AechoLiu    14 年前

    一个值得注意的例子是qsort(),它需要一个回调函数来比较两个项目。 回调函数可以在运行时保留一些行为。

    如果一些行为应该在运行时由客户端动态决定,那么我将要求客户端提供回调函数。