关闭

Day17.STL编程

260人阅读 评论(0) 收藏 举报
分类:

老习惯,回忆一下;

函数指针

语法,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、  回调函数的入口地址缓存到框架库中

clitSocket_SetEncFunc(void *handle, EncData encDataCallbak, void *ref, int refLen)

2、回调函数入口直接放在参数中

cltSocketSend_enc(void *handle, unsigned char *buf,  int buflen, EncData encDataCallbakFunc, void *ref, int refLen)

 

二、加密 解密 业务模型抽象

实现 动态库 加密解密业务模型抽象

通过定义函数指针类型;函数指针做函数参数实现

typedef int (*EncData)(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen);

typedef int (*DecData)(unsigned char *inData, int inDataLen, unsigned char *outData, int *outDataLen, void *Ref, int RefLen);

我的理解:

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

推荐的书籍:





















0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:43962次
    • 积分:776
    • 等级:
    • 排名:千里之外
    • 原创:39篇
    • 转载:6篇
    • 译文:0篇
    • 评论:14条
    最新评论