C++类内多线程创建和调用成员变量的两种方式

文章介绍了如何在C++中使用std::thread构造函数调用类对象的成员函数,一种是通过将类对象作为静态成员函数的参数,另一种是利用std::bind绑定非静态成员函数和this指针。

std::thread的构造函数的参数不能是非静态成员函数,需要静态成员函数,如果想要在类内创建线程并调用类对象的成员变量,需要做一些处理,实现方式如下:

第一种:

类的对象作为线程的静态成员函数传入类指针使用,在类里调用

#include <iostream> 
#include <thread>
#include <unistd.h>

using namespace std;

class MyTest
{
public:
	void run();
	static void func_work(MyTest*);

private:
	int n = 0;
};


void MyTest::work(MyTest* ptr)
{
	while (1)
	{
		cout << (ptr->n)++ << endl;
		sleep(2);
	}
}

void MyTest::run()
{
	std::thread my_thread(func_work, this);
	my_thread.detach();
}

int main()
{
	MyTest* test = new MyTest;
	test->run();

	while (1);
	return 0;
}

第二种:

不必把线程函数定义为静态函数,直接用std::bind函数把函数和this指针绑定

#include <iostream> 
#include <thread>
#include <unistd.h>

using namespace std;

class MyTest
{
public:
	void run();
	void func_work();

private:
	int n = 0;
};


void MyTest::func_work()
{
	while (1)
	{
		cout << n++ << endl;
		sleep(2);
	}
}

void MyTest::run()
{
    //std::thread my_thread(std::bind(std::mem_fn(&MyTest::func_work), this));
	std::thread my_thread(std::bind(&MyTest::func_work, this));
	my_thread.detach();
}

int main()
{
	MyTest* test = new MyTest;
	test->run();

	while (1);
	return 0;
}

<think>我们正在讨论MFC中的CDC如何应用到自定义中。根据引用[1],CDC封装了Windows GDI函数,并且有多个派生(如CWindowDC、CPaintDC等)用于特定绘图操作。引用[2]提到MFC通过继承建立联系,而引用[4]则给出了一个获取安全DC句柄的例子。 为了在自己的中使用CDC,通常有以下几种方式: 1. 在中包含一个CDC指针或引用,或者直接包含一个CDC对象(但注意CDC是抽象基,不能直接实例化,所以通常使用其派生)。 2. 在创建CDC的派生对象(如CClientDC、CWindowDC等)来执行绘图操作。 3. 通过获取已有的CDC指针(如在视图的OnDraw函数中传入的pDC)来使用。 具体步骤: - 首先,需要包含相应的MFC头文件(如afxwin.h)。 - 然后,在自定义中,可以定义一个CDC指针成员变量,或者直接使用CDC派生对象。 - 注意CDC资源的管理,避免资源泄漏(通常使用RAII原则,或者利用MFC的自动释放机制,例如CClientDC在构造时获取DC,析构时自动释放)。 示例:假设我们有一个自定义的图形绘制CMyDrawer,我们希望在内部使用CDC进行绘图。 方法1:在中保存CDC指针(通常由外部传入,不负责释放) ```cpp #include <afxwin.h> class CMyDrawer { public: void SetDC(CDC* pDC) { m_pDC = pDC; } void DrawSomething() { if (m_pDC) { m_pDC->Rectangle(10, 10, 100, 100); // 绘制一个矩形 } } private: CDC* m_pDC; // 注意:这个指针指向的CDC对象由外部管理,本不负责释放 }; ``` 方法2:在内部创建CDC派生对象(如针对窗口的CClientDC) ```cpp #include <afxwin.h> class CMyDrawer { public: CMyDrawer(CWnd* pWnd) { m_pDC = new CClientDC(pWnd); // 创建CClientDC对象,关联到指定窗口 } ~CMyDrawer() { delete m_pDC; // 注意:需要自己释放,因为是我们new的 } void DrawSomething() { m_pDC->Rectangle(10, 10, 100, 100); } private: CDC* m_pDC; // 这里我们创建的是CClientDC,但用CDC指针指向它 }; ``` 注意:方法2中,我们必须在析构函数中释放m_pDC指向的对象。也可以使用智能指针(如果项目支持C++11或更高版本)来管理。 方法3:使用栈上的CDC派生对象(更安全,自动释放) 如果我们不需要在整个的生命周期内持有DC,而只是在某个成员函数中使用,那么可以在函数内部创建CDC派生对象,这样当函数结束时,对象会自动析构并释放DC。 ```cpp void CMyDrawer::DrawSomething(CWnd* pWnd) { CClientDC dc(pWnd); // 栈上对象,自动释放 dc.Rectangle(10, 10, 100, 100); } ``` 引用[4]提到了获取安全DC句柄的方法:`GetSafeHdc()`,我们可以通过已有的CDC对象获取其句柄(HDC),然后保存这个HDC(因为CDC对象可能被销毁,但句柄可能被其他地方使用,所以需要谨慎)。但通常,我们更推荐使用CDC对象本身。 另外,根据引用[3](虽然内容不完整,但标题提示CDC详细教程),我们可以进一步学习CDC的各种成员函数,如绘图、文本输出等。 总结:在自己的中使用CDC,主要考虑CDC对象的生命周期所有权。如果只是临时使用,在函数内部创建CDC派生对象(如CClientDC)是最安全的方式。如果需要在对象生命周期内多次使用,则可以考虑保存CDC指针(由外部传入并管理)或者保存一个CDC派生对象(自己管理)。 注意:由于CDC是MFC,使用时需要确保在MFC项目环境中。 相关问题: 1. 如何在自己的中使用CDC进行双缓冲绘图? 2. 如何在非窗口中获取CDC? 3. CDC有哪些常用的绘图函数? </think>### 在C++中将MFC的CDC数据型应用到自定义的方法 在MFC开发中,将CDC集成到自定义需要遵循以下核心原则实现步骤: #### 一、基本原则 1. **继承关系** 自定义应直接或间接派生自`CObject`或`CDC`相关派生(如引用[2]所述),符合MFC层次结构规范。 2. **资源管理** 采用RAII(资源获取即初始化)原则管理DC资源,防止资源泄漏(引用[4]强调的安全句柄获取)。 3. **功能复用** 通过组合或继承复用CDC的GDI封装能力(引用[1]指出CDC封装了大部分Windows GDI函数)。 #### 二、具体实现方案 ##### 方案1:组合方式(推荐) ```cpp #include <afxwin.h> // MFC核心头文件 class CMyCustomClass { public: CMyCustomClass(CWnd* pTargetWnd) : m_dc(pTargetWnd) // 关联目标窗口 { // 初始化自定义参数 } void CustomDrawing() { // 使用封装的CDC对象 m_dc.Rectangle(10, 10, 200, 150); // 绘制矩形 m_dc.TextOutW(50, 50, L"自定义绘制"); // 输出文本 } private: CClientDC m_dc; // 组合CDC派生对象 }; ``` **优势**: - 自动管理DC生命周期(构造函数获取DC,析构函数自动释放) - 无需手动调用`ReleaseDC`(引用[4]的安全句柄管理) ##### 方案2:继承方式 ```cpp class CMyDrawingDC : public CClientDC { public: CMyDrawingDC(CWnd* pWnd) : CClientDC(pWnd) {} void DrawCustomShape() { // 直接使用继承的CDC方法 Ellipse(30, 30, 150, 100); SetTextColor(RGB(255,0,0)); TextOutW(40, 60, L"继承方式示例"); } }; // 使用示例 void CMyView::OnDraw(CDC* /*pDC*/) { CMyDrawingDC dc(this); // 创建自定义DC dc.DrawCustomShape(); // 调用扩展功能 } ``` #### 三、关键注意事项 1. **窗口关联** 必须绑定有效的窗口对象(如`CView`/`CDialog`派生),否则DC无效: ```cpp // 错误示例(无窗口关联) CClientDC dc(nullptr); // 将引发断言错误 ``` 2. **跨函数传递** 传递CDC指针时使用`GetSafeHdc()`获取安全句柄(引用[4]方法): ```cpp void ExternalAPI(HDC hdc); // 第三方API void CMyClass::Render() { CClientDC dc(this); ExternalAPI(dc.GetSafeHdc()); // 安全传递句柄 } ``` 3. **资源释放** 避免手动释放组合/继承的DC对象,MFC已实现自动释放机制(引用[1]的封装特性)。 #### 四、高级应用场景 ```cpp // 双缓冲绘图实现 void CMyClass::DoubleBufferDrawing() { CClientDC dc(this); CDC memDC; memDC.CreateCompatibleDC(&dc); // 创建内存DC CBitmap bmp; bmp.CreateCompatibleBitmap(&dc, 500, 500); memDC.SelectObject(&bmp); // 在内存DC绘制 memDC.FillSolidRect(0, 0, 500, 500, RGB(255,255,255)); memDC.Ellipse(100, 100, 400, 400); // 一次性输出到屏幕 dc.BitBlt(0, 0, 500, 500, &memDC, 0, 0, SRCCOPY); } ``` > **最佳实践**:优先选择组合方式集成CDC,符合面向对象设计原则,避免继承层次过深导致的维护问题(引用[2]的MFC继承结构)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值