(8)面向对象编程

1.从一个Thread类图出发

  • (1)下面的Thread类是一个抽象类:不能实例化对象
    下面的TestThread是一个派生类,具体类
  • (2)每个Thread类都有自己的执行体,可以用Run方法来表示,不同的TestThread类执行体是不一样的。
    可以将该方法提升到基类做一个抽象的接口,就是那个纯虚函数Run()。
    在这里插入图片描述

2.用例解析

  • 使用cmake编译
  • 目录如下:
    在这里插入图片描述
  • 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 $*

//直接输入./build.sh进行编译
  • 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)//生成的可执行程序的名称:Thread_test
target_link_libraries(Thread_test pthread)//链接pthread库
  • Thread_test.cpp
#include "Thread.h"
#include <unistd.h>
#include <iostream>
using namespace std;

//派生类公有继承Thread基类
//只要继承Thread抽象类,那么不同的线程体就有不同的执行体,即Run()接口
//面向对象编程会暴露Thread抽象类,而基于对象编程不会暴露Thread抽象类
class TestThread : public Thread
{
public:
	TestThread(int count) : count_(count)
	{
		cout<<"TestThread ..."<<endl;
	}

	~TestThread()
	{
		cout<<"~TestThread ..."<<endl;
	}

private:
	void Run()//成员函数Run()可以访问数据成员count_
	{
		while (count_--)
		{
			cout<<"this is a test ..."<<endl;
			sleep(1);//#include <unistd.h>
		}
	}

	int count_;
};

int main(void)
{
	/*
	TestThread t(5);//派生类对象
	t.Start();//成员函数Start()第一个参数隐含了一个this指针,指向派生类对象本身,相当于&t

	t.Join();//等待pthread子线程函数退出,防止主线程退出了,子线程还没有运行

	//////////////////////////////////
	t.Run();//直接写这样的代码表示在主线程当中运行,虽然结果一样
	//////////////////////////////////
	
	*/

	/*
		注意:线程对象的生命周期和线程的生命周期时不一样的!!
		线程生命周期的销毁,是程序结束的时候;而且线程执行完毕,线程对象可能还未被销毁。
		所以,如何实现线程执行完毕,线程对象能够自动销毁?
		答案:所以该对象是动态创建对象才可以,所以new个对象
	*/
	TestThread* t2 = new TestThread(5);
	t2->SetAutoDelete(true);
	t2->Start();
	t2->Join();

	//死循环的作用:防止主线程结束了,子线程还没有执行
	for (; ; )
		pause();

	return 0;
}
  • Thread.cpp
#include "Thread.h"
#include <iostream>
using namespace std;


Thread::Thread() : autoDelete_(false)
{
	cout<<"Thread ..."<<endl;
}

Thread::~Thread()
{
	cout<<"~Thread ..."<<endl;
}

void Thread::Start()
{
	//这里的this指针指向的是派生类,因为我们后面肯定用的是派生类

	pthread_create(&threadId_, NULL, ThreadRoutine, this);//线程id,线程属性,线程的入口函数,入口函数的参数用this指针传递

	//这里run函数为啥不能作为入口函数??因为run是普通的成员函数,隐含的第一个参数是Thread*,即this指针,
	//调用的时候是thiscall的约定,某个寄存器会保存this指针,而
	//ThreadRoutine是普通函数的调用约定,可以编写全局的函数,也可以用static 成员函数,这样的话,
	//调用就不会隐含传递一个this指针过来!!
}

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

//因为run()才是线程要执行的执行体,所以这里要调用run方法。但是不能直接调用,因为ThreadRoutine是静态成员函数,
//不能调用非静态的成员函数run()!!!因为他没有this指针,
//上面的this指针已经传递到ThreadRoutine的入口arg
void* Thread::ThreadRoutine(void* arg)
{
	//main中的t.Start();表明:这是基类指针指向派生类对象,基类指针调用的是派生类实现的虚函数
	//1)这就是虚函数的多态,若pthread类是库实现的,main中创建线程,相当于库回调了Run()方法,即(2)虚函数具有回调功能
	Thread* thread = static_cast<Thread*>(arg);//将派生类指针转化为基类指针,因为静态成员函数不能访问非静态的成员
	//基类指针不要直接访问private函数,但是这里能用
	thread->Run();
	//基类指针不要指针访问private成员,但是这里能用
	if (thread->autoDelete_)//这里也要注意:静态成员函数不能访问非静态的成员,所以要通过指针来访问
		delete thread;//线程执行完毕了,应该销毁它,后面调用的时候,这里的thread指的是派生类对象,即t2
	return NULL;
}

void Thread::SetAutoDelete(bool autoDelete)
{
	autoDelete_ = autoDelete;
}
  • Thread.h
#ifndef _THREAD_H_
#define _THREAD_H_

#include <pthread.h>

//Thread抽象基类
class Thread
{
public:
	Thread();//构造函数
	virtual ~Thread();//必须是纯虚析构函数,因为该类是作为多态基类,若不使用多态基类,可以不使用纯虚析构函数。
					  //若不用的话,会导致派生类的资源释放的时候不完全

	void Start();//线程的启动方法
	void Join();//线程的join函数,主要调用pthread_join

	void SetAutoDelete(bool autoDelete);

private:
	static void* ThreadRoutine(void* arg);//加了static就没有隐含的this指针了!!
	//纯虚函数别定义成private的,但是这里能用而已
	virtual void Run() = 0;//不同的线程函数的执行体,线程的抽象接口
	pthread_t threadId_;//线程id
	bool autoDelete_;//比如实现一个线程池,我们希望线程如果执行结束,能自动销毁线程对象
};

#endif // _THREAD_H_
  • 测试:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢打篮球的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值