C++回调机制的几种实现方式

2023-05-16



Callback

Callback的本质是设置一个函数指针进去,然后在需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型。
比如下面的示例代码,我们在Download完成时需要触发一个通知外面的事件:

typedef void (__stdcall *DownloadCallback)(const char* pURL, bool bOK);
void DownloadFile(const char* pURL, DownloadCallback pCallback)
{
    ……
    pCallback (pURL, true);
}
void __stdcall OnDownloadFinished(const char* pURL, bool bOK)
{
    ……
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Sink

Sink的本质是你按照对方要求实现一个C++接口,然后把你实现的接口设置给对方,对方需要触发事件时调用该接口, COM中连接点就是居于这种方式。还是以上面的Download为例(你调用对方的下载类实现下载功能):

/*对方要求的接口*/
class IDownloadSink
{
public:
    virtual void OnDownloadFinished(const char* pURL, bool bOK) = 0;
};
/*对方的实现*/
class CMyDownloader
{
public:
    CMyDownloader(IDownloadSink* pSink) : m_pSink(pSink)  { }

    void DownloadFile(const char* pURL)
    {
        ……
        if(m_pSink != NULL)
            m_pSink->OnDownloadFinished(pURL, true);
    }

private:
    IDownloadSink* m_pSink;
};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
/*你的实现*/
class CMyFile: public IDownloadSink
{
public:
    void Download()
    {
        CMyDownloader downloader(this);
        downloader.DownloadFile("www.baidu.com");
    }

    virtual void OnDownloadFinished(const char* pURL, bool bOK)
    {
        ……
    }
}
  • 15

Delegate

Delegate的本质是设置成员函数指针给对方,然后让对方在需要触发事件时调用。C#中用Delegate的方式实现Event,让C++程序员很是羡慕,C++中因为语言本身的关系,要实现Delegate还是很麻烦的。上面的例子我们用Delegate的方式实现如下:

class CDownloadDelegateBase
{
public:
    virtual void Fire(const char* pURL, bool bOK) = 0;
};

/*模板类,实现代理函数的调用*/
template<typename O, typename T>
class CDownloadDelegate: public CDownloadDelegateBase
{
    typedef void (T::*Fun)(const char*, bool);
public:
    CDownloadDelegate(O* pObj = NULL, Fun pFun = NULL)
        :m_pFun(pFun), m_pObj(pObj)
    { }    
    virtual void Fire(const char* pURL, bool bOK)
    {
         if(m_pFun != NULL && m_pObj != NULL)
         {
              (m_pObj->*m_pFun)(pURL, bOK);
         }
    }
private:
    Fun m_pFun;
    O* m_pObj;
};

/*模板函数,创建代理*/
template<typename O, typename T>
CDownloadDelegate<O,T>* MakeDelegate(O* pObject, void (T::*pFun)(const char* pURL, bool))
{
     return new CDownloadDelegate<O, T>(pObject, pFun);
}

/*代理函数管理*/
typedef vector<CDownloadDelegateBase*> CDownloadDelegates;
class CDownloadEvent
{
public:
    ~CDownloadEvent()
    {
        CDownloadDelegates::iterator it = m_arDelegates.begin();
        while (it != m_arDelegates.end())
        {
            delete *it;
            ++it;
        }
        m_arDelegates.clear();
    }

    void operator += (CDownloadDelegateBase* p)
    {
        m_arDelegates.push_back(p);
    }

    void operator -= (CDownloadDelegateBase* p)
    {
        CDownloadDelegates::iterator it = remove(m_arDelegates.begin(), m_arDelegates.end(), p);
        while (it != m_arDelegates.end())
        {
            delete *it;
            ++it;
        }
        m_arDelegates.erase(it, m_arDelegates.end());
    }

    void operator()(const char* pURL, bool bOK)
    {
        CDownloadDelegates::iterator it = m_arDelegates.begin();
        while (it != m_arDelegates.end())
        {
            (*it)->Fire(pURL, bOK);
            ++it;
        }
    }
private:
    CDownloadDelegates m_arDelegates;
};

class CMyDownloaderEx
{
public:
    void DownloadFile(const char* pURL)
    {
        ……
        downloadEvent(pURL, true);
    }
    CDownloadEvent downloadEvent;
};

/*应用*/
class CMyFileEx
{
public:
    void download()
    {
        CMyDownloaderEx downloader;
        /*添加代理函数*/
        downloader.downloadEvent += MakeDelegate(this, &CMyFileEx::OnDownloadFinished);
        downloader.DownloadFile("www.baidu.com");
    }

    virtual void OnDownloadFinished(const char* pURL, bool bOK)
    {
       ……
    }
};
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

可以看到Delegate的方式代码量比上面其他2种方式多多了,并且上面是固定参数数量和类型的实现方式,如果要实现可变参数,要更加麻烦的多,具体可参考:
http://www.codeproject.com/Articles/11464/Yet-Another-C-style-Delegate-Class-in-Standard-C
http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible

std::function(since C++ 11, vs2010)

template< class R, class... Args >
class function<R(Args...)>
  
  
  • 1
  • 2
  • 1
  • 2

类模板std :: function是一个通用的多态函数包装器。std :: function的实例可以存储,复制和调用任何可调用的目标:函数、lambda表达式、绑定表达式或其他函数对象。

#include <functional>
#include <iostream>

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};

void print_num(int i)
{
    std::cout << i << '\n';
}

int main()
{
    // store a free function
    std::function<void(int)> f1 = print_num;
    f1(-9);

    // store a lambda
    std::function<void()> f2 = []() { print_num(123); };
    f2();

    // store the result of a call to std::bind
    std::function<void()> f3 = std::bind(print_num, 12345);
    f3();

    // store a call to a member function
    std::function<void(const Foo&, int)> f4 = &Foo::print_add;
    Foo foo(13579);
    f4(foo, 1);
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

std::mem_fn (since C++ 11, vs2010)

template< class R, class T >
/*unspecified*/ mem_fn(R T::* pm);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...));
template< class R, class T, class... Args >
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) &);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const &);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile &);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile &);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) &&);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const &&);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile &&);
template< class R, class T, class... Args > 
/*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile &&);
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

函数模板std :: mem_fn生成指向成员函数的指针的包装对象,它可以存储,复制和调用指向成员函数的指针。 在调用std :: mem_fn时,可以使用对象的引用和指针(包括智能指针)。

/* Use mem_fn to store and execute a member function:*/
#include <functional>
#include <iostream> 
struct Foo {  
    void display_greeting() {    
        std::cout << "Hello, world.\n";  
    }  
    void display_number(int i) {    
        std::cout << "number: " << i << '\n';  
    }
}; 

int main() 
{
    Foo foo;
    auto func_greet = std::mem_fn(&Foo::display_greeting);
    func_greet(foo);  
    auto func_display = std::mem_fn(&Foo::display_number);
    func_display(foo, 42);
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
#include <iostream>
#include <functional>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include <algorithm> 
int main()
{
    /*Pass a member function to std::transform to create a sequence of numbers:*/
    std::vector<std::string> words = {"It", "is", "a", "test"};
    std::vector<std::unique_ptr<std::string>> words2;    
    words2.emplace_back(new std::string("another"));    
    words2.emplace_back(new std::string("test"));

    std::vector<std::size_t> lengths;    
    std::transform(words.begin(), 
                  words.end(),
                  std::back_inserter(lengths), 
    std::mem_fn(&std::string::size)); 
    // uses references to strings    

    std::transform(words2.begin(),                 words2.end(), 
    std::back_inserter(lengths),
    std::mem_fn(&std::string::size)); 
    // uses unique_ptr to strings    
    std::cout << "The string lengths are ";   

    for(auto n : lengths) 
        std::cout << n << ' ';    
    std::cout << '\n';
}

template<class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, 
OutputIt d_first, UnaryOperation unary_op)
{
    while (first1 != last1) {
        *d_first++ = unary_op(*first1++);    
    }    
    return d_first;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

小结

1) Callback方法是面向过程的,使用简单而且灵活,正如C语言本身;
2) Sink方法是面向对象的,在C++里使用较多, 可以在一个Sink里封装一组回调接口,适用于一系列比较固定的回调事件;
3) Delegate方法也是面向对象的,和Sink封装一组接口不同,Delegate的封装是以函数为单位,粒度比Sink更小更灵活;
4) std::function和std::bind组合使用也可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类的非静态成员函数时(本质上讲全局函数和静态成员函数没有区别,使用方法上除了静态成员函数在引用时要在前面加域作用符classname::外,没有其它任何区别;事实上全局函数也有可能放入命名空间或者使用全局域作用符,例如 namespace::function() 或::function,这样不仅本质上相同,形势上也与静态成员函数一致了)。在Effective C++中ITEM35建议使用该方法实现Strategy模式,实际上也可以用于代替callback 函数模仿C#中的event对象,而这里只能实现一个函数,实际上如果function<>模板实现了operator+以后,再在 function对象中维护一个列表,便可以实现C#中的event特性,即Delegate。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++回调机制的几种实现方式 的相关文章

  • C#String.Split (string[], StringSplitOptions) 多参数分割得到数组

    public string Split string separator StringSplitOptions options 参数 separator 类型 xff1a System String 分隔此字符串中的子字符串的字符串数组 不
  • vim选中字符复制/剪切/粘贴

    问题描述 xff1a https www cnblogs com luosongchao p 3193153 html vim 中选中指定字符 xff0c 进行复制 剪切 粘贴 问题解决 xff1a 进入vim中visual模式 xff0c
  • for循环本质

    菜鸟 xff1a 为什么在for循环里重复定义变量不会报错 xff1f 如下代码1 xff0c 因为重复定义了两个变量 a xff0c 编译器报错 void main int a int a return 如下代码2 xff0c 用for循
  • 常见功能类库及功能

    BitConverter 数据转换类 Array 数组类 ComboBox 列表文本框
  • 基础概念笔记

    1 声明和定义的区别 声明 xff1a 是解释内存是什么类型 定义 xff1a 是赋值
  • C#中DataGridView控件使用大全

    c datagridview 分类 xff1a C C xff0b xff0b C DataGridView 动态添加新行 xff1a DataGridView控件在实际应用中非常实用 xff0c 特别需要表格显示数据时 可以静态绑定数据源
  • DataTable转成字符串复制到txt文本的小例子

    自己写了个DataTable转成字符串的方法 复制代码代码如下 public static string DataTableToString DataTable dt string dtstring 61 34 34 for int i 6
  • C#实现字符串按多个字符采用Split方法分割得到数组

    String字符串如何按多个字符采用Split方法进行分割呢 xff1f 本文提供VS2005和VS2003的实现方法 xff0c VS2005可以用下面的方法 xff1a string agentInfo 61 userInfo Attr
  • C#实现 UDP简单广播

    csharp view plain copy print 代码 Code highlighting produced by Actipro CodeHighlighter freeware http www CodeHighlighter
  • 事件委托 EventHandler 。

    事件就是当对象或类状态发生改变时 xff0c 对象或类发出的信息或通知 发出信息的对象或类称为 34 事件源 34 对事件进行处理的方法称为 34 接收者 34 通常事件源在发出状态改变信息时 它并不知道由哪个事件接收者来处理 这就需要一种
  • XML文件转换成字符串互相转换操作

    System Xml XmlDocument doc 61 new System Xml XmlDocument 新建对象 doc Load 34 filePath 34 XML文件路径 string content 61 doc Inne
  • dataSerVer操作方法总结

    using System using System Collections Generic using System Linq using System Text using System Data using System IO usin
  • ubuntu无法ping www.baidu.com问题

    1 使用ifconfig 查看ip 发现地址正常 2 查看dns ip地址正常 还是无法通ping www baidu com 后来把静态地址配置该为动态地址配置后成功
  • ToolStrip和ToolStripButton的用法

    假设我的toolstrip里面有三个toolstripbutton分别是tsp1 tsp2 tsp3依次加载 xff0c 如何设置tsp3显示在toolstrip的第一个按钮 ToolStripItem tsm 61 toolStrip1
  • c#多维数组的建立及操作 总结

    1C 如何定义和使用多维数组 不建议使用ArrayList xff0c 当数组里的元素是值类型在操作的时候会出现大量的装箱与拆箱步骤性能会损失许多 xff0c 而是应该用什么类型的元素创建什么类型的数组 xff0c 除非你的元素有交叉或不确
  • 在TreeView查找某一节点

    在TreeView 查找某一节点 xff0c 通常有两种方法 xff0c 一种是递归的 xff0c 一种不是递归 xff0c 但都是深度优先算法 其中 xff0c 非递归方法效率高些 xff0c 而递归算法要简洁一些 第一种 xff0c 递
  • C#的数据类型总结

    C 的数据类型可以分为3 类 数值类型 引用类型 指针类型 指针类型仅在不安全代码中使用 一 值类型 值类型包括简单值类型和复合型类型 简单值类型可以再细分为整数类型 字符类型 实数类型和布尔类型 xff1b 而复合类型则是简单类型的复合
  • C#中OpenFileDialog获取文件名和文件路径的常用方法.

    System IO Path GetFullPath openFileDialog1 FileName 绝对路径 System IO Path GetExtension openFileDialog1 FileName 文件扩展名 Syst
  • 操作XML 报错:根级别上的数据无效 和 给定编码中的字符无效 解决办法

    根级别上的数据无效 解决如下 private void button1 Click object sender EventArgs e try XmlDocument doc 61 new XmlDocument string file 6
  • DataGridRow的创建

    用原始datagridview的列名赋值的时候找不到列名 xff0c 用索引就可以 xff0c 不知道是怎么回事 DataGridViewRow dr 61 new DataGridViewRow dr CreateCells this d

随机推荐

  • 常用方法和属性列表

    BitConvert islittle 判断大小端 Array reverse 反排列数组
  • System.Windows.Forms.Timer与System.Timers.Timer的区别

    NET Framework里面提供了三种Timer xff1a System Windows Forms Timer System Timers Timer System Threading Timer VS NET 2005默认只有一个T
  • c++中scanf和printf

    xfeff xfeff scanf函数一般格式是 xff1a scanf 格式控制 输出表列 printf函数的一般格式是 printf 格式控制 输出表列 例3 4 用scanf和printf函数进行输入和输出 include lt io
  • win10无法上网,连网显示黄色三角形探号

    1 打开网络属性 2 打开无线电源开关 3 重启电脑 4 使用网络疑难解答 5 重启DHCP
  • 计算机程序的思维逻辑 (12) - 函数调用的基本原理

    xfeff xfeff 栈 上节我们介绍了函数的基本概念 xff0c 在最后我们提到了一个系统异常java lang StackOverflowError xff0c 栈溢出错误 xff0c 要理解这个错误 xff0c 我们需要理解函数调用
  • c语言中函数调用的原理

    xfeff xfeff 一 函数参数传递机制的基本理论 函数参数传递机制问题在本质上是调用函数 xff08 过程 xff09 和被调用函数 xff08 过程 xff09 在调用发生时进行通信的方法问题 基本的参数传递机制有两种 xff1a
  • 栈中函数调用原理_详解

    xfeff xfeff 函数调用是程序设计中的重要环节 xff0c 本文就函数调用的过程进行分析 一 eip ebp esp介绍 EIP xff0c EBP xff0c ESP都是系统的寄存器 xff0c 里面存储的是些地址 xff0c 我
  • C++中如何定义动态数组

    xfeff xfeff 首先 xff1a 为什么需要动态定义数组呢 xff1f 这是因为 xff0c 很多情况下 xff0c 在预编译过程阶段 xff0c 数组的长度是不能预先知道的 xff0c 必须在程序运行时动态的给出 但是问题是 xf
  • 数组和指针、数组指针和指针数组

    xfeff xfeff 数组和指针 数组指针和指针数组 函数指针和指针函数 数组标识符的意义 静态和动态创建的数组的本质区别 标识符类型判断方法 html view plain copy print include lt iostream
  • 函数中的指针分配的内存怎么释放

    xfeff xfeff 被调用函数里动态分配的内存要不要手动释放 20 我想手动释放来着 xff0c 但是指针是在被调用函数里声明的 xff0c 在调用函数里释放不了 我的被调用函数返回的就是这个指针 xff0c 我也不能在被调用函数里释放
  • duilib各种布局的作用,相对布局与绝对布局的的意义与用法

    duilib各种布局的作用 xff0c 相对布局与绝对布局的的意义与用法 原文 http blog csdn net zhuhongshu article details 38531447 主题 Duilib 转载请说明原出处 xff0c
  • wpf中:xaml中的命名空间的引入方法

    xfeff xfeff wpf中 xff1a xaml中的命名空间的引入 本文章已收录于 xff1a 在xaml中如有要使用c 数据类型 xff0c 那么需要引入c 的命名空间 xff0c 如需要使用String类 xff0c 则需要引入S
  • WPF Application启动界面设置——

    xfeff xfeff 本文章已收录于 xff1a 设置WPF从不同界面启动可以通过设置 StartupUri 属性完成 http blog csdn net bamboo slit article details 7164848 设置St
  • 【2.路由器接口配置】

    1 ip route 0 0 0 0 43 0 0 0 0 43 接口的IP地址 2 ip address ip地址 43 子网掩码 pos framing sdh sonet pos flag s1s0 2 0 3 4 5
  • Linux(debian7)操作基础(七)之LightDM详解及使用

    LightDM自启动默认登录 使用命令sudo vim etc lightdm lightdm conf 将 autologin user 61 更改为 autologin user 61 登录用户名 xff0c 保存退出 更改主机名 xf
  • c#读取指定路径的配置文件

    xfeff xfeff ExeConfigurationFileMap map 61 new ExeConfigurationFileMap map ExeConfigFilename 61 64 34 F App1 config 34 C
  • C#创建com组件

    xfeff xfeff 本文详细阐述如何用C 创建COM组件 xff0c 并能用VC6 0等调用 并附有完整测试通过的代码 废话不多说 xff0c 下面开始介绍 xff1a 开发工具 xff1a VS2010 VS2010命令提示符在 xf
  • Windows下静态链接库的使用

    xfeff xfeff 静态链接是指将一个或多个静态链接库 xff08 lib文件 xff09 在Link时期和调用该库的程序一起形成exe文件 网上关于静态链接库的理论叙述多且详尽 xff0c 我就不再造轮子了 xff0c 此处仅说明一下
  • 异步消息的传递-回调机制

    xfeff xfeff 软件模块之间总是存在着一定的接口 xff0c 从调用方式上 xff0c 可以把他们分为三类 xff1a 同步调用 回调和异步调用 同步调用是一种阻塞式调用 xff0c 调用方要等待对方执行完毕才返回 xff0c 它是
  • C++回调机制的几种实现方式

    xfeff xfeff Callback Callback的本质是设置一个函数指针进去 xff0c 然后在需要触发某个事件时调用该方法 比如Windows的窗口消息处理函数就是这种类型 比如下面的示例代码 xff0c 我们在Download