老习惯,回忆一下;
函数指针
语法,3种定义方法:
//1. 定义一个函数类型
typedef int Func1(int);
Func1 myfunc1;
//2. 定义一个指向函数类型的指针类型
typedef int(*Func2)(int);
Func2 myfunc2;
//3. 直接定义一个函数指针,并且赋值
void(*Func3)() = NULL;
函数名称就代表函数的入口地址, 函数名本身就是一个指针
//函数名称就代表函数的入口地址, 函数名本身就是一个指针
int test(int a)
{
return a*a;
}
具体的使用看代码:
#include "iostream"
using namespace std;
//函数名称就代表函数的入口地址, 函数名本身就是一个指针
int test(int a)
{
return a*a;
}
typedef int Func(int);
void main()
{
Func *myfunc = NULL;
myfunc = &test;
myfunc = test;
myfunc(2);
system("pause");
}
函数指针做函数参数------回调
语法基础:
函数指针做函数参数的两种方法
//1. 第一种方法
int libfun(int(*pFunc)(int));
//2. 第二种方法
typedef int(*pFunc)(int a, int b);
int libfun(pFunc myfunc);
反向调用:
回调机制原理:
当具体事件发生时,调用者通过函数指针调用具体函数
回调机制将调用者和被调函数分开,两者互补依赖
回调机制的最大好处是:
任务的实现和任务的调用 可以耦合 (提前进行接口的封装和设计)
int libfun(int(*pFunc)(int));
这样,利用多态的这种性质就可以实现上面的代码(80年代写的代码)调用(int (*pFunc))(int)(2020年写的代码),这就是多态最重要的最终的目的。
正向调用:
1. 通过VS编译器加载动态库函数:
2. 程序员主动调用动态链接库
//客户端初始化 获取handle上下
typedef int(*CltSocketInit)(void **handle);
//客户端发报文
typedef int(*CltSocketSend)(void *handle, unsigned char *buf, int buflen);
//客户端收报文
typedef int(*CltSocketRev)(void *handle, unsigned char *buf, int *buflen);
//客户端释放资源
typedef int(*CltSocketDestory)(void *handle);
//在这个函数里面完成动态库的加载
//利用winapi
void CMFCMyDlg::OnBnClickedButton()
{
// TODO: 在此添加控件通知处理程序代码
HINSTANCE hInstance = NULL;
hInstance = ::LoadLibrary("c:/socketclient.dll");
CltSocketInit cltSocketInit = (CltSocketInit)::GetProcAddress(hInstance, "cltSocketInit");
CltSocketSend cltSocketSend = (CltSocketSend)::GetProcAddress(hInstance, "cltSocketSend");
CltSocketRev cltSocketRev = (CltSocketRev)::GetProcAddress(hInstance, "cltSocketRev");
CltSocketDestory cltSocketDestory = (CltSocketDestory)::GetProcAddress(hInstance, "cltSocketDestory");
void *handle = NULL;
unsigned char buf[100];
int buflen = 10;
memcpy(buf, "ddddddddddssssssssss", 10);
unsigned char out[100] = { 0 };
int outlen = 0;
int ret = cltSocketInit(&handle);
ret = cltSocketSend(handle, buf, buflen);
ret = cltSocketRev(handle, out, &outlen);
ret = cltSocketDestory(handle);
printf("out:%s", out);
AfxMessageBox("this is a button messagebox");
}
如何把一个普通的动态库变成一个业务模型框架,需要做的工作 一、需要把第三方业务入口传进来(回调函数的入口地址传进来) 传进来有两种方式
二、加密 解密 业务模型抽象 实现 动态库 加密解密业务模型抽象 通过定义函数指针类型;函数指针做函数参数实现
|
我的理解:
1. 在main函数文件的头文件中,设置要回调的函数
typedef int (*EncData)(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen);
2. 在main函数文件中,设置具体的回调函数实现, 参数类型和返回值都要和上面的设置函数保持一致
int myEncData(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen)
{
/**********************************************
<pre name="code" class="cpp"> **********************************************/
}
3. 在socket或动态库文件中,在handle结构体加入回调函数参数
typedef struct _SCK_HANDLE {
char version[16];
char serverip[16];
int serverport;
unsigned char * buf ;
int buflen;
//加入回调函数的信息
EncData myEncDataFunc;
void *encRef;
int encRefLen;
DecData myDecDataFunc;
void *decRef;
int decRefLen;
}SCK_HANDLE;
4. 在socke或动态库文件中,设置回调函数的函数体内将回调函数的地址加入上面的结构体中
ITCAST_FUNC_EXPORT(int)
clitSocket_SetEncFunc(void *handle, EncData encDataCallbak, void *ref, int refLen)
{
SCK_HANDLE *sh = NULL;
sh = (SCK_HANDLE *)handle;
sh->myEncDataFunc = encDataCallbak;
/****************************************
****************************************/
}
5. 当调用cltSocketSend_enc发送函数时加密:
cltSocketSend_enc(void *handle, unsigned char *buf, int buflen, EncData encDataCallbakFunc, void *ref, int refLen)
{
/*****************************************
*****************************************/
//如果有加密回调函数,则执行回调
if (sh->myEncDataFunc != NULL)
{
sh->buf = (unsigned char *)malloc(sizeof(char)*(buflen+128));
if (sh->buf == NULL)
{
return rv;
}
rv = encDataCallbakFunc(buf, buflen, sh->buf, &(sh->buflen), ref, refLen);
if (rv != 0)
{
ITCAST_LOG(__FILE__, __LINE__,LogLevel[4], rv,"func cltSocketSend(): (sh->myEncDataFunc [%d]", rv);
return rv;
}
}
/*****************************************
*****************************************/
}
泛型编程
泛型编程的本质就是类型参数化
template模版编程参看上一节:http://blog.csdn.net/jorg_zhao/article/details/46771667
templa分为函数模版和类模板
函数模版:
1. 函数模版可以像普通函数一样被重载
2. C++编译器优化考虑普通函数
3. 如果函数模版可以产生一个更好的匹配,那么选择模版
4. 可以通过空模版实参列表的语法限制编译器只通过函数匹配
5. 函数模版不允许自动类型转化
6. 普通函数能够进行自动类型转换
函数模版的本质:
1. 编译器并不是把函数模版处理成能够处理任何类型的函数
2. 编译器从函数模版通过具体类型产生不同的函数
3. 编译器会对函数模版进行两次编译
4. 在声明的地方对模版代码本身进行编译
5. 在掉用的地方对参数替换后的代码进行编译
语法基础
</pre><pre name="code" class="cpp">template<typename T>
void swap2(T &a, T &b)
{
T c;
c = a;
a = b;
b = c;
}
void main111()
{
//泛型编程的调用方式有两种
//自动类型推导
int x =1, y =2;
swap2(x, y);
printf("x:%d y:%d \n", x, y);
float x1= 1.0, y1 = 2.0;
//具体类型调用
swap2<float>(x1, y1);
printf("x1:%f y1:%f \n", x1, y1);
system("pause");
}
函数模版代码
template<class T>
void printfArray(T *a, int num)
{
cout<<endl;
for (int i=0; i<num; i++)
{
cout<<a[i]<<" ";
}
}
类模板:
class BB : public AA<int>
{
public:
//BB(int a, int b) : AA(a)
BB(int a, int b) : AA<int>(a)
{
this->b = b;
}
private:
int b;
};
#include <iostream>
using namespace std;
template<class T>
class Complex
{
public:
Complex( T r =0, T i =0 );
Complex(T a) { Real = a ; Image = 0 ; }
void print() const;
friend Complex<T>operator+(Complex<T>&c1,Complex<T>&c2)
{
T r = c1.Real + c2.Real ; T i = c1.Image+c2.Image ;
return Complex<T>( r, i ) ;
}
//friend Complex operator- ( const Complex<T> & c1, const Complex<T> & c2 );
//friend Complex operator- ( const Complex<T> & c );
private:
T Real, Image ;
};
template<class T>
Complex<T>::Complex( T r, T i )
{
Real = r ; Image = i ;
}
// template<class T>
// Complex<T>operator+(Complex<T>&c1,Complex<T>&c2)
// {
// T r = c1.Real + c2.Real ; T i = c1.Image+c2.Image ;
// return Complex<T>( r, i ) ;
// }
template<typename T>
void Complex<T>::print()const
{
cout << '(' << Real << " , " << Image << ')' << endl;
}
void main61()
{
Complex<int>c1(1, 2);
Complex<int>c2(3, 4);
Complex<int>c3 = c1 + c2;
c3.print();
system("pause");
}
********************************************************************************************************************
STL
网上搜罗的网址:http://pan.baidu.com/s/1qWtBcZU
C++标准模板库STL.pdf:http://pan.baidu.com/s/1hqvnpCK
STL算法集合:http://pan.baidu.com/s/1i3AeuJN
什么是STL?
STL standard template library 它是泛型编程实现的。
摘自:http://pan.baidu.com/s/1qWtBcZU,此文中给出了一些基础知识。
C6. 定义容器类的模板的头文件
头文件 | 描 述 |
<vector> | 定义vector序列模板,这是一个大小可以重新设置的数组类型,比普通数组更安全、更灵活 |
<list> | 定义list序列模板,这是一个序列的链表,常常在任意位置插入和删除元素 |
<deque> | 定义deque序列模板,支持在开始和结尾的高效插入和删除操作 |
<queue> | 为队列(先进先出)数据结构定义序列适配器queue和priority_queue |
<stack> | 为堆栈(后进先出)数据结构定义序列适配器stack |
<map> | map是一个关联容器类型,允许根据键值是唯一的,且按照升序存储。multimap类似于map,但键不是唯一的。 |
<set> | set是一个关联容器类型,用于以升序方式存储唯一值。multiset类似于set,但是值不必是唯一的。 |
<bitset> | 为固定长度的位序列定义bitset模板,它可以看作固定长度的紧凑型bool数组 |
兑现到代码上:
最简单的来个:
#include "iostream"
#include "vector"
using namespace std;
void printArray(vector<int> &v)
{
int size = v.size();
for (int i = 0; i < size; i++)
{
cout << v[i] << endl;
}
}
void main()
{
//定义一个数组(弹性)
vector<int> v1(5); //int v1[5];
for (int i = 0; i < 5; i++)
{
v1[i] = i + 1;
}
vector<int> v2(10);
v2 = v1;
for (int i = 0; i < 5; i++)
{
cout << v2[i] << endl;
}
v2.resize(0);
cout << v2.size() << endl;
system("pause");
}
如果加入结构体呢???????????
#include "iostream"
#include "vector"
using namespace std;
struct Teacher
{
int age;
char name[20];
};
void main()
{
Teacher t1, t2, t3;
t1.age = 10;
t2.age = 20;
t3.age = 30;
vector<Teacher> v;
v.push_back(t1);
v.push_back(t2);
v.push_back(t3);
for (int i = 0; i < v.size(); i++)
{
cout << v[i].age << endl;
}
system("pause");
}
如果结构体定义的是一个指针呢????????
#include "iostream"
#include "vector"
using namespace std;
struct Teacher
{
int age;
char name[20];
};
void main()
{
Teacher t1, t2, t3;
t1.age = 10;
t2.age = 20;
t3.age = 30;
vector<Teacher *> v;
v.push_back(&t1);
v.push_back(&t2);
v.push_back(&t3);
for (int i = 0; i < v.size(); i++)
{
struct Teacher *tmp = v[i];
cout << tmp->age << endl;
}
system("pause");
}
********************************************************************************************************************
栈和队列
#include "iostream"
#include "stack"
using namespace std;
void main()
{
//定义一个栈
stack<int> s;
//栈赋值
for (int i = 0; i < 5; i++)
{
s.push(i + 1);
}
//栈遍历
while (!s.empty())
{
//获取栈顶元素
int tmp = s.top();
//弹出栈顶元素-----不弹出上面的元素,就无法访问下面的元素
s.pop();
}
system("pause");
}
栈中加入结构体
#include "iostream"
#include "stack"
using namespace std;
struct Teacher
{
int age;
char name[10];
};
void printStack(stack<Teacher> &s)
{
while (!s.empty())
{
//获取栈的元素
cout << s.top().age << endl;
//弹出栈顶元素
s.pop();
}
}
void main()
{
Teacher t1, t2, t3;
t1.age = 10;
t2.age = 20;
t3.age = 30;
//定义一个栈
stack<Teacher> s;
//栈赋值
s.push(t1);
s.push(t2);
s.push(t3);
printStack(s);
system("pause");
}
队列
#include "iostream"
#include "queue"
using namespace std;
void main()
{
//建一个队列
queue<int> q;
//向队列中添加一个元素
for (int i = 0; i < 5; i++)
{
q.push(i);
}
while (!q.empty())
{
//获取队列头元素
int tmp = q.front();
cout << tmp << endl;
//弹出队列元素
q.pop();
}
system("pause");
}
队列和结构体
#include "iostream"
#include "queue"
using namespace std;
struct Teacher
{
int age;
char name[10];
};
void printQueue(queue<Teacher*> q)
{
while (!q.empty())
{
Teacher *tmp = q.front();
cout << tmp->age << endl;
q.pop();
}
}
void main()
{
queue<Teacher*> q;
Teacher t1, t2, t3;
t1.age = 11;
t2.age = 22;
t3.age = 33;
q.push(&t1);
q.push(&t2);
q.push(&t3);
printQueue(q);
system("pause");
}
list链表
#include "iostream"
#include "list"
using namespace std;
void main()
{
//建立一个链表
list<int> l;
int len = l.size();
cout << len << endl;
//链表尾部增加元素
for (int i = 0; i < 5; i++)
{
l.push_back(i);
}
len = l.size();
cout << len << endl;
//链表迭代器--迭代器就是一个指针
list<int>::iterator current = l.begin();
while (current != l.end())
{
cout << *current << endl;
current++;
}
cout << "*****************" << endl;
//把链表的首位置赋给迭代器指针
current = l.begin();
current++;
current++;
current++;
//在X位置插入,原先X位置及以后元素后移
l.insert(current, 100);
for (list<int>::iterator p = l.begin(); p != l.end(); p++)
{
cout << (*p) << endl;
}
system("pause");
}
********************************************************************************************************************
STL一个算法
#include "iostream"
#include "vector"
#include "algorithm"
#include "cmath"
using namespace std;
//打印上层业务数据结构,是上层的事,stl不会关心
void callbackFunc(int &v)
{
cout << v <<" ";
}
int comp(const int &a, const int &b)
{
return a < b;
}
void main()
{
//定义一个vector,并赋值
vector<int> v(10);
for (int i = 0; i < 5; i++)
{
v[i] = rand() % 10;
}
//打印
for (int i = 0; i < 5; i++)
{
cout << v[i] <<" ";
}
cout << endl;
//stl提供的函数(利用回调函数)
for_each(v.begin(), v.end(), callbackFunc);
cout << endl;
//1. stl提供的排序函数(默认)
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), callbackFunc);
cout << endl;
//2. stl提供的排序函数(回调函数)
sort(v.begin(), v.end(), comp);
for_each(v.begin(), v.end(), callbackFunc);
cout << endl;
system("pause");
}
常用算法:
STL算法集合:http://pan.baidu.com/s/1i3AeuJN
推荐的书籍: