文章目录

  • 1.boost bind/function
  • 2.代码
  • 3.面向对象编程方法与基于对象的编程方法的区别

1.boost bind/function

  • boost bind/function库的出现,替代了stl中的mem_fun,ptr_fun,bind1st,bin2nd等函数
  • 函数适配器,从一种函数接口适配成另一种接口
  • eg:
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace std;
class Foo
{
public:
	//成员函数隐含了第一个参数:Foo*,用于指向对象本身
	void memberFunc(double d, int i, int j)
	{
		cout << d << endl;//打印0.5
		cout << i << endl;//打印100       
		cout << j << endl;//打印10
	}
};
int main()
{
	Foo foo;
	//适配成新接口:void f(int),即:将4个参数的成员函数适配成一个参数的函数
	//Void是返回类型,int是形参类型
	
	/*
	(1)&foo, 0.5, _1, 10对应于成员函数的4个参数
	_1代表占位符,还有_2,_3,表示boost function的参数
	
	(2)相当于调用了:
	取地址&foo是一个指针
	(&foo)->memberFunc(0.5,100,10)
	Boost::bind作用:将一种函数接口转换为另一种类型的函数接口
	*/
	boost::function<void (int)> fp = boost::bind(&Foo::memberFunc, &foo, 0.5, _1, 10);
	fp(100);
	return 0;
}
==============================================================================

#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace std;
class Foo
{
public:
	void memberFunc(double d, int i, int j)
	{
		cout << d << endl;//打印0.5
		cout << i << endl;//打印100       
		cout << j << endl;//打印10
	}
};
int main()
{
	Foo foo;
	boost::function<void (int, int)> fp = boost::bind(&Foo::memberFunc, &foo, 0.5, _1, _2);
	fp(100, 200);
	boost::function<void (int, int)> fp2 = boost::bind(&Foo::memberFunc, boost::ref(foo), 0.5, _1, _2);
	fp2(55, 66);
	return 0;
}
  • 注意在std::bind和std::thread中,如果要按照引用进行传递某变量,需要使用std::ref,否则就是值传递即深拷贝,看下面的eg:
#include <iostream>
#include <functional>
#include<vector>

using namespace std;

void f(int& a, int& b, int& c)
{
    cout << "in function a = " << a << "  b = " << b << "  c = " << c << endl;
    cout << "in function a = " << &a << "  b = " << &b << "  c = " << &c << endl;
    a += 1;
    b += 10;
    c += 100;
}

int main() {

    int n1 = 1, n2 = 10, n3 = 100;
    int& r1 = n1;
    int& r2 = n2;

    function<void()> f1 = bind(f, r1, r2, ref(n3));

    f1();
    cout << "out function a = " << n1 << "  b = " << n2 << "  c = " << n3 << endl;
    cout << "out function a = " << &n1 << "  b = " << &n2 << "  c = " << &n3 << endl;
    return 0;
}
  • 测试:
in function a = 1  b = 10  c = 100
in function a = 0x505670  b = 0x505674  c = 0x5055a0
out function a = 1  b = 10  c = 200
out function a = 0x5055a8  b = 0x5055a4  c = 0x5055a0
  • eg:
#include <iostream>
#include <future>
#include <thread>

int fun(int x, std::promise<int>& p) {
	x++;
	x *= 10;
	p.set_value(x);
	std::cout << std::this_thread::get_id() << std::endl;
	return x;
}


int main()
{
	std::promise<int> p;
	std::future<int> fu = p.get_future();        // 并将结果返回给future
	std::thread t(fun, 1, std::move(p));
	std::cout << fu.get() << std::endl;          // 当promise还没有值的时候在此等待
	std::cout << std::this_thread::get_id() << std::endl;
	t.join();
	return 0;
}
  • eg2:Thread类图
typedef boost::function<void ()> ThreadFunc;

(9)基于对象的编程风格_ios

2.代码

  • 包含的文件有:Thread.h,Thread.cpp,Thread_test.cpp,CMakeLists.txt,build.sh
  • Thread.h
#ifndef _THREAD_H_
#define _THREAD_H_

#include <pthread.h>
#include <boost/function.hpp>

class Thread
{
public:
	typedef boost::function<void ()> ThreadFunc;//返回类型为void,形参为空
	explicit Thread(const ThreadFunc& func);//explicit表示可以显示调用,阻止隐士地转换构造

	void Start();
	void Join();

	void SetAutoDelete(bool autoDelete);

private:
	static void* ThreadRoutine(void* arg);
	void Run();
	ThreadFunc func_;//通过构造函数传递进来
	pthread_t threadId_;
	bool autoDelete_;
};

#endif // _THREAD_H_
  • Thread.cpp
#include "Thread.h"
#include <iostream>
using namespace std;


Thread::Thread(const ThreadFunc& func) : func_(func), autoDelete_(false)
{
}

void Thread::Start()
{
	pthread_create(&threadId_, NULL, ThreadRoutine, this);
}

void Thread::Join()
{
	pthread_join(threadId_, NULL);
}

void* Thread::ThreadRoutine(void* arg)
{
	Thread* thread = static_cast<Thread*>(arg);
	thread->Run();
	if (thread->autoDelete_)
		delete thread;
	return NULL;
}

void Thread::SetAutoDelete(bool autoDelete)
{
	autoDelete_ = autoDelete;
}

void Thread::Run()
{
	func_();
}
  • Thread_test.cpp
#include "Thread.h"
#include <boost/bind.hpp>
#include <unistd.h>
#include <iostream>
using namespace std;

class Foo
{
public:
	Foo(int count) : count_(count)
	{
	}

	void MemberFun()
	{
		while (count_--)
		{
			cout<<"this is a test ..."<<endl;
			sleep(1);
		}
	}

	void MemberFun2(int x)
	{
		while (count_--)
		{
			cout<<"x="<<x<<" this is a test2 ..."<<endl;
			sleep(1);
		}
	}

	int count_;
};

void ThreadFunc()
{
	cout<<"ThreadFunc ..."<<endl;
}

void ThreadFunc2(int count)
{
	while (count--)
	{
		cout<<"ThreadFunc2 ..."<<endl;
		sleep(1);
	}
}


int main(void)
{
	//创建线程对象,因为:typedef boost::function<void ()> ThreadFunc;//返回类型为void,形参为空
	Thread t1(ThreadFunc);//线程的执行体:ThreadFunc
	
	//下面的不符合接口转化,就用boost::bind进行转化,其返回的函数相当于:boost::function<vid()>
	//线程的执行体:ThreadFunc2
	Thread t2(boost::bind(ThreadFunc2, 3));//相当于返回了 boost::function<void ()> ,普通函数ThreadFunc2可以省略&符号
	Foo foo(3);//MemberFun会执行3次
	//线程的执行体:&Foo::MemberFun
	Thread t3(boost::bind(&Foo::MemberFun, &foo));//成员函数ThreadFunc2不可以省略&符号,&foo是第一个参数
	Foo foo2(3);
	Thread t4(boost::bind(&Foo::MemberFun2, &foo2, 1000));
	/*
	若将Foo foo2(3);注释掉,则:
	(&foo)->MemberFun();
	(&foo)->MemberFun2();
	两个对象随便调用了不同的成员函数,但是都访问了同一个count,相当于2个线程访问了共享变量count,会存在同步问题,两个线程会相互影响
	count的值,因为这里的线程不知道谁先谁后运行
	
	*/

	//有4个线程
	t1.Start();
	t2.Start();
	t3.Start();
	t4.Start();

	t1.Join();
	t2.Join();
	t3.Join();
	t4.Join();


	return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.6)

project(pas CXX)

set(CXX_FLAGS -g -Wall)
set(CMAKE_CXX_COMPILER "g++")
string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}")

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

add_executable(Thread_test Thread_test.cpp Thread.cpp)
target_link_libraries(Thread_test pthread)
add_executable(bf_test bf_test.cpp)
  • build.sh
#!/bin/sh

set -x

SOURCE_DIR=`pwd`
BUILD_DIR=${BUILD_DIR:-../build}

mkdir -p $BUILD_DIR \
  && cd $BUILD_DIR \
  && cmake $SOURCE_DIR \
  && make $*

3.面向对象编程方法与基于对象的编程方法的区别

  • 面向对象编程方法:
    EchoServer类继承TcpServer类
    当有客户端连接服务端的时候,网络库net的EventLoop会调用TcpServer类中的纯虚函数OnConnection,
    app提供了EchoServer类,他实现了Onconnection,OnMessage,Onclose这3个方法,
    当事件被网络库捕捉到的时候,TcpServer会回调上述的3个方法(基类指针指向派生类对象,调用派生类的虚函数),通过虚函数的回调方法
  • 基于对象的编程方法
    将成员函数进行bind,当网络库收到事件后,都会回调下面三个成员函数
    为啥叫基于对象?因为用到了class,底层还是回调了成员函数
class EchoServer
{
	public:
		EchoServer()
		{
			server.SetConnectionCallback(boost::bind(onConnection));
			server.SetConnectionCallback(boost::bind(onConnection));
			server.SetConnectionCallback(boost::bind(onConnection));
		}
		void onConnection(){}
		void onMessage()
		void onClose
		TcpServer server
}
  • 总结:
    (1)如果用C语言写的话,就是注册三个全局函数到网络库,网络库通过函数指针来回调
    (2)面向对象风格,是用一个EchoServer继承抽象类TcpServer,实现3个接口Onconnection,OnMessage,Onclose
    (3)基于对象风格,用一个EchoServer包含一个具体类Tcpserver对象,在构造函数中用boost::bind来注册3个成员函数Onconnection,OnMessage,Onclose