植物大战僵尸杂交版破解C++实现

文章目录

  • 前言
  • 准备工作:基地址与偏移
  • UI界面设计和绑定
    • 项目模板
    • 总览图
    • 生成与实现
    • 信号处理
      • 1、阳光值更新:BTN1
      • 2、三种钱币值更新:BTN2-BTN4
      • 3、冷却刷新:BTN5
      • 4、锁定阳光:check1
      • 5、无冷却:check2
      • 6、OnTimer()和OnClose()处理函数
      • 7、其余未描述部分参考

前言

最近出来的PVZ杂交版又掀起一波热潮,在各大短视频平台也有一席之地,借助工具Cheat Engine,写了个简单的植物大战僵尸杂交版破解程序,话不多说,我们来看如何实现的。
工具:Cheat Engine、visual studio (MFC支持)、植物大战僵尸杂交版

准备工作:基地址与偏移

通过CE寻找基地址的工作可以参考其他人的博客:
通过CE寻找游戏基址1
通过CE寻找游戏基址2
这里直接给出对应内容:【基址+偏移】
阳光值:0x006A9EC0 + 0x00000768 + 0x00005560
银币值:0x006A9EC0 + 0x0000082C + 0x00000208
金币值:0x006A9EC0 + 0x0000082C + 0x0000020C
钻石值:0x006A9EC0 + 0x0000082C + 0x00000210
冷却值:0x006A9EC0 + 0x00000768 + 0x00000144 +{
0x00000070, 0x000000C0, 0x00000110, 0x00000160,
0x000001B0, 0x00000200, 0x00000250, 0x000002A0,
0x000002F0, 0x00000340, 0x00000390, 0x000003E0,
0x00000430, 0x00000480, 0x000004D0, 0x00000520
对应卡牌栏目第几章卡牌,索引就是几,实际上卡牌不会超过14张,只要给出14个就行了,找到前几个偏移量之后可以按照规律往后推测。
}

UI界面设计和绑定

项目模板

使用MFC应用程序,选择基于对话框选项

总览图

UI设计图

生成与实现

1、依此双击按钮、单选框,studio会自动建立信号与函数的映射。
2、Dlg.h中添加成员变量:

public:
UINT sunvalue;	//阳光
UINT money_a;	//银币
UINT money_b;	//金币
UINT money_c;	//钻石
int check1;		//锁定阳光	check 的状态
int check2;		//无冷却	check 的状态

3、Dlg.cpp中进行内容绑定:

void CPVZCrackerDlg::DoDataExchange(CDataExchange* pDX){
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT1, sunvalue);	//将edit1的内容与sunvalue绑定,以下同理
	DDX_Text(pDX, IDC_EDIT2, money_a);	
	DDX_Text(pDX, IDC_EDIT3, money_b);	
	DDX_Text(pDX, IDC_EDIT4, money_c);	
	DDX_Check(pDX, CHECK1, check1);
	DDX_Check(pDX, CHECK2, check2);
}

4、如何让check选择时,实现阳光锁定和刷新冷却呢?
可以在check勾选时,开启定时器,每隔0.5s进行模拟点击刷新事件来达到效果
因此需要引入定时器模块,给出相关博客(主要参考2)
MFC中如何使用定时器:1
MFC中如何使用定时器:2
创建出void XXXXXDlg::OnTimer(UINT_PTR nIDEvent)。
当勾选状态时,打开计时器,未勾选状态时,关闭计时器即可

5、经过上面的操作后,Dlg.h内容大致如下:


// PVZCrackerDlg.h: 头文件
//

#pragma once

// CPVZCrackerDlg 对话框
class CPVZCrackerDlg : public CDialogEx
{
// 构造
public:
	CPVZCrackerDlg(CWnd* pParent = nullptr);	// 标准构造函数
	UINT sunvalue;	//阳光
	UINT money_a;	//银币
	UINT money_b;	//金币
	UINT money_c;	//钻石
	int check1;		//锁定阳光	check 的状态
	int check2;		//无冷却	check 的状态
// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_PVZCRACKER_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedButton1();
	afx_msg void OnBnClickedButton2();
	afx_msg void OnBnClickedButton3();
	afx_msg void OnBnClickedButton4();
	afx_msg void OnBnClickedButton5();

	afx_msg void OnBnClickedCheck1();
	afx_msg void OnBnClickedCheck2();
	afx_msg void OnTimer(UINT_PTR nIDEvent);

	int TIM_X ;
	afx_msg void OnClose();
};

信号处理

1、阳光值更新:BTN1

void CPVZCrackerDlg::OnBnClickedButton1(){
	// 修改阳光
	UpdateData(TRUE);	//先进行数据更新
	HWND PVZ;			//获取窗口句柄
	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");//这里需要对应游戏窗口名。
	DWORD pid = 0;
	GetWindowThreadProcessId(PVZ, &pid);	//获取进程id
	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);//打开进程,获取所有权

	SIZE_T ipread = 0;           //下面要用的参数,实际上往往忽略,但不写又不行

	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
	DWORD offset1 = 0x00000768;
	DWORD offset2 = 0x00005560;
	//[A]->B 表示将A地址里的值拿到B中,不加[]代表立即数下文同理,如有错误欢迎指正
	//[base]->sunbase
	DWORD sunbase = 0;
	ReadProcessMemory(handle, LPCVOID(base), &sunbase, sizeof(DWORD), &ipread);

	//[sunbase+offset1]->sunoffset1
	DWORD sunoffset1 = 0;
	ReadProcessMemory(handle, LPCVOID(sunbase + offset1), &sunoffset1, sizeof(DWORD), &ipread);

	//sunvalue -> [sunoffset1+offset2]
	DWORD svalue = sunvalue;
	WriteProcessMemory(handle, LPVOID(sunoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
}

2、三种钱币值更新:BTN2-BTN4

void CPVZCrackerDlg::OnBnClickedButton2(){
	// TODO: 在此添加控件通知处理程序代码
	// 修改银币
	UpdateData(TRUE);
	HWND PVZ;
	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
	DWORD pid = 0;
	GetWindowThreadProcessId(PVZ, &pid);
	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

	SIZE_T ipread = 0;           //下面要用的参数

	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
	DWORD offset1 = 0x0000082C;
	DWORD offset2 = 0x00000208;

	//[base]->moneybase
	DWORD moneybase = 0;
	ReadProcessMemory(handle, LPCVOID(base), &moneybase, sizeof(DWORD), &ipread);

	//[moneybase+offset1]->moneyoffset1
	DWORD moneyoffset1 = 0;
	ReadProcessMemory(handle, LPCVOID(moneybase + offset1), &moneyoffset1, sizeof(DWORD), &ipread);

	//money_a -> [moneyoffset1+offset2]
	DWORD svalue = money_a;
	WriteProcessMemory(handle, LPVOID(moneyoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
}
void CPVZCrackerDlg::OnBnClickedButton3(){
	// TODO: 在此添加控件通知处理程序代码
	// 修改金币
	UpdateData(TRUE);
	HWND PVZ;
	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
	DWORD pid = 0;
	GetWindowThreadProcessId(PVZ, &pid);
	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

	SIZE_T ipread = 0;           //下面要用的参数

	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
	DWORD offset1 = 0x0000082C;
	DWORD offset2 = 0x0000020C;

	//[base]->moneybase
	DWORD moneybase = 0;
	ReadProcessMemory(handle, LPCVOID(base), &moneybase, sizeof(DWORD), &ipread);

	//[moneybase+offset1]->moneyoffset1
	DWORD moneyoffset1 = 0;
	ReadProcessMemory(handle, LPCVOID(moneybase + offset1), &moneyoffset1, sizeof(DWORD), &ipread);

	//money_b -> [moneyoffset1+offset2]
	DWORD svalue = money_b;
	WriteProcessMemory(handle, LPVOID(moneyoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
}


void CPVZCrackerDlg::OnBnClickedButton4(){
	// TODO: 在此添加控件通知处理程序代码
	// 修改钻石
	UpdateData(TRUE);
	HWND PVZ;
	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
	DWORD pid = 0;
	GetWindowThreadProcessId(PVZ, &pid);
	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

	SIZE_T ipread = 0;           //下面要用的参数

	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
	DWORD offset1 = 0x0000082C;
	DWORD offset2 = 0x00000210;

	//[base]->moneybase
	DWORD moneybase = 0;
	ReadProcessMemory(handle, LPCVOID(base), &moneybase, sizeof(DWORD), &ipread);

	//[moneybase+offset1]->moneyoffset1
	DWORD moneyoffset1 = 0;
	ReadProcessMemory(handle, LPCVOID(moneybase + offset1), &moneyoffset1, sizeof(DWORD), &ipread);

	//money_a -> [moneyoffset1+offset2]
	DWORD svalue = money_c;
	WriteProcessMemory(handle, LPVOID(moneyoffset1 + offset2), &svalue, sizeof(DWORD), &ipread);
}

3、冷却刷新:BTN5

void CPVZCrackerDlg::OnBnClickedButton5(){
	// 修改冷却
	UpdateData(TRUE);
	HWND PVZ;
	PVZ = ::FindWindow(L"MAINWINDOW", L"植物大战僵尸杂交版v2.0");
	DWORD pid = 0;
	GetWindowThreadProcessId(PVZ, &pid);
	HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

	SIZE_T ipread = 0;           //下面要用的参数

	DWORD base = 0x006A9EC0;	 //数据基地址偏移量等由CE给出。
	DWORD offset1 = 0x00000768;
	DWORD offset2 = 0x00000144;
	DWORD offset3[16] = {
		0x00000070, 0x000000C0, 0x00000110, 0x00000160,
		0x000001B0, 0x00000200, 0x00000250, 0x000002A0,
		0x000002F0, 0x00000340, 0x00000390, 0x000003E0,
		0x00000430, 0x00000480, 0x000004D0, 0x00000520
	};

	//[base]->freshbase
	DWORD freshbase = 0;
	ReadProcessMemory(handle, LPCVOID(base), &freshbase, sizeof(DWORD), &ipread);

	//[freshbase+offset1]->freshoffset1
	DWORD freshoffset1 = 0;
	ReadProcessMemory(handle, LPCVOID(freshbase + offset1), &freshoffset1, sizeof(DWORD), &ipread);

	//[freshoffset1+offset2]->freshoffset2
	DWORD freshoffset2 = 0;
	ReadProcessMemory(handle, LPVOID(freshoffset1 + offset2), &freshoffset2, sizeof(DWORD), &ipread);

	//1 ->[freshoffset2+offset3]
	DWORD freshvalue = 1;	//1代表冷却完毕	其他代表正在冷却
	for (int i = 0; i < 16; ++i)
		WriteProcessMemory(handle, LPVOID(freshoffset2 + offset3[i]), &freshvalue, sizeof(DWORD), &ipread);
}

4、锁定阳光:check1

void CPVZCrackerDlg::OnBnClickedCheck1(){
	// TODO: 在此添加控件通知处理程序代码
	CButton* pBtn = (CButton*)GetDlgItem(CHECK1);
	int checked = pBtn->GetCheck();	//获取check状态
	//实际上可以直接check1
	switch (checked){
	case 1: {
		SetTimer(1, 500, NULL);	//设置500ms为周期的定时器,标签为1,并开启
		break;
	}
	case 0: {
		KillTimer(1);			//关闭标签为1的定时器
		break;
	}
	default:
		break;
	}
}

5、无冷却:check2

void CPVZCrackerDlg::OnBnClickedCheck2(){
	// TODO: 在此添加控件通知处理程序代码
	CButton* pBtn = (CButton*)GetDlgItem(CHECK2);
	int checked = pBtn->GetCheck();

	switch (checked) {
	case 1: {
		SetTimer(2, 500, NULL);
		break;
	}
	case 0: {
		KillTimer(2);
		break;
	}
	default:
		break;
	}
}

6、OnTimer()和OnClose()处理函数

void CPVZCrackerDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch (nIDEvent){
	case 1: OnBnClickedButton1(); break;
	case 2: OnBnClickedButton5(); break;
	default:
		break;
	}
	CDialogEx::OnTimer(nIDEvent);
}


void CPVZCrackerDlg::OnClose()
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	KillTimer(1);
	KillTimer(2);
	CDialogEx::OnClose();
}

7、其余未描述部分参考


// PVZCrackerDlg.cpp: 实现文件
#include "pch.h"
#include "framework.h"
#include "PVZCracker.h"
#include "PVZCrackerDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CPVZCrackerDlg 对话框
CPVZCrackerDlg::CPVZCrackerDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_PVZCRACKER_DIALOG, pParent){
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	check1 = 0;
	check2 = 0;
	sunvalue = 5000;
	money_a = 10000;
	money_b = 10000;
	money_c = 10000;
	TIM_X = 0;
}

void CPVZCrackerDlg::DoDataExchange(CDataExchange* pDX){
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT1, sunvalue);	//将edit1的内容与sunvalue绑定,以下同理
	DDX_Text(pDX, IDC_EDIT2, money_a);	
	DDX_Text(pDX, IDC_EDIT3, money_b);	
	DDX_Text(pDX, IDC_EDIT4, money_c);	
	DDX_Check(pDX, CHECK1, check1);
	DDX_Check(pDX, CHECK2, check2);
}

BEGIN_MESSAGE_MAP(CPVZCrackerDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CPVZCrackerDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CPVZCrackerDlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_BUTTON3, &CPVZCrackerDlg::OnBnClickedButton3)
	ON_BN_CLICKED(IDC_BUTTON4, &CPVZCrackerDlg::OnBnClickedButton4)
	ON_BN_CLICKED(IDC_BUTTON5, &CPVZCrackerDlg::OnBnClickedButton5)

	
	ON_BN_CLICKED(CHECK1, &CPVZCrackerDlg::OnBnClickedCheck1)
	ON_BN_CLICKED(CHECK2, &CPVZCrackerDlg::OnBnClickedCheck2)
	ON_WM_TIMER()
	ON_WM_CLOSE()
END_MESSAGE_MAP()


// CPVZCrackerDlg 消息处理程序

BOOL CPVZCrackerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	this->SetWindowTextW(L"植物大战僵尸杂交版破解 by 和八哥的环球探险");
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

// 如果向对话框添加最小化按钮,则需要下面的代码来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,这将由框架自动完成。

void CPVZCrackerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CPVZCrackerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/666048.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux上传文件

在finalshell中连接的Linux系统中&#xff0c;输入命令rz然后选择windows中的文件即可。

透视茅台股东大会三大关键词:稳定、竞争力、创新

执笔 | 尼 奥 编辑 | 扬 灵 “让我们携手共同致力于茅台的稳定、健康、可持续发展。”上任刚满一个月的贵州茅台党委书记、董事长张德芹&#xff0c;在5月29日的贵州茅台酒股份有限公司2023年度股东大会上迎来首秀。 张德芹在40多分钟脱稿演讲与30多分钟互动环节中&#x…

TiDB学习9:Ti Cloud简介

目录 1. 为什么选择TiDB 2. 多租户 3. TiDB架构 4. 什么是TiDB Cloud 5. TiDB Cloud Provider Region 6. TiDB Cloud 入门 6.1 在浏览器中打开TiDB Cloud 6.2 创建您的账户 6.3 Developer Tier 与Dedicated Tier 6.3.1 Developer Tier 6.3.2 Dedicated Tier 6.3.2.…

项目纪实 | 版本升级操作get!GreatDB分布式升级过程详解

某客户项目现场&#xff0c;因其业务系统要用到数据库新版本中的功能特性&#xff0c;因此考虑升级现有数据库版本。在升级之前&#xff0c;万里数据库项目团队帮助客户在本地测试环境构造了相同的基础版本&#xff0c;导入部分生产数据&#xff0c;尽量复刻生产环境进行升级&a…

【NVM】nvm常用命令,切换node版本命令

nvm常用的命令&#xff0c;切换node版本命令 nvm 查看支持安装的node版本 nvm list available nvm安装指定版本node nvm install 版本号 例如&#xff1a;nvm install 10.24.1 nvm查看本机安装所有node版本 nvm list nvm切换node版本 nvm use 10.24.1 检测当前node版本 node -…

玄机平台应急响应—Linux日志分析

1、前言 啥是日志呢&#xff0c;日志就是字面意思&#xff0c;用来记录你干了啥事情。日志大体可以分为网站日志和系统日志&#xff0c;网站日志呢就是记录哪个用户在哪里什么时候干了啥事&#xff0c;以及其它的与网站相关的事情。系统日志呢&#xff0c;就是记录你的电脑系统…

动态分配函数参数用二级指针的作用

文章目录 前言一、案例 前言 在一些情况下&#xff0c;我们需要在函数内部动态地分配内存来存储结构体&#xff0c;并且需要在函数外部访问该结构体。在这种情况下&#xff0c;可以使用二级指针作为函数参数来实现动态内存分配&#xff0c;并且在函数外部使用指针访问结构体。…

12V转19V4A升压恒压WT3207

12V转19V4A升压恒压WT3207 WT3207是款高效的PWM升压控制器&#xff0c;采用SO-8封装设计。该控制器经过优化以适应低输入电压应用&#xff0c;具有从5V至36V的广泛输入电压范围&#xff0c;适用于需要提高12V、15V和19V系统电压的场合&#xff0c;特别是对于两节或三节锂离子电…

Apache Doris 基础 -- 数据表设计(数据模型)

Versions: 2.1 1、模型概览 本主题从逻辑角度介绍了Doris中的数据模型&#xff0c;以便您可以在不同的业务场景中更好地使用Doris。 基本概念 本文主要从逻辑的角度描述Doris的数据模型&#xff0c;旨在帮助用户在不同的场景更好地利用Doris。 在Doris中&#xff0c;数据在…

GEE 10m近实时 LULC 数据集Dynamic World

Google Earth Engine 和 Dynamic World Google 利用其地球引擎&#xff08;Earth Engine&#xff09;和人工智能&#xff08;AI&#xff09;平台技术&#xff0c;推出了 Dynamic World 数据库&#xff0c;能够提供接近实时的全球土地环境数据。Dynamic World 是基于 Google Ear…

【Gradle】Gradle的本地安装和使用

目录 1、Gradle 的安装 2、集成 IntelliJ IDEA 3、使用 Gradle Gradle 完全兼容 Maven 和 Ivy 仓库&#xff0c;你可以从中检索依赖也可以发布你的文件到仓库中&#xff0c;Gradle 提供转换器能把 Maven 的构建逻辑转换成 Gradle 的构建脚本。 1、Gradle 的安装 Gradle 的…

卷积网络迁移学习:实现思想与TensorFlow实践

摘要&#xff1a;迁移学习是一种利用已有知识来改善新任务学习性能的方法。 在深度学习中&#xff0c;迁移学习通过迁移卷积网络&#xff08;CNN&#xff09;的预训练权重&#xff0c;实现了在新领域或任务上的高效学习。 下面我将详细介绍迁移学习的概念、实现思想&#xff0c…

【Qt】Qt界面美化指南:深入理解QSS样式表的应用与实践

文章目录 前言&#xff1a;1. 背景介绍2. 基本语法3. QSS 设置方式3.1. 设置全局样式3.2. 从文件加载样式表3.3. 使用 Qt Designer 编辑样式 总结&#xff1a; 前言&#xff1a; 在当今这个视觉至上的时代&#xff0c;用户界面&#xff08;UI&#xff09;的设计对于任何软件产…

嵌入式Linux复制剪切删除指令详解

指令操作 1. cp 复制指令 a. 用法&#xff1a;cp [ 选项 ] [ 源文件或目录 ] [ 目标文件或目录 ]&#xff1b; b. 用途&#xff1a;用于复制文件或目录&#xff1b; c. 通常情况下&#xff0c;复制的都不是空文件夹&#xff0c;所以直接使用 cp 复制空文件会失败&#xff0…

[ROS 系列学习教程] 建模与仿真 - Xacro 语法

ROS 系列学习教程(总目录) 本文目录 一、属性与属性块二、数学表达式三、宏3.1 宏的基本使用3.2 属性块做为宏的入参3.3 任意数量元素做为宏的入参3.4 指定多个块元素的处理顺序3.5 宏嵌套3.6 默认参数3.7 局部属性 四、Rospack 命令五、包含其他 xacro 文件六、条件语句七、YA…

C#中接口的显式实现与隐式实现及其相关应用案例

C#中接口的显式实现与隐式实现 最近在学习演化一款游戏项目框架时候&#xff0c;框架作者巧妙使用接口中方法的显式实现来变相对接口中方法进行“密封”&#xff0c;增加实现接口的类访问方法的“成本”。 接口的显式实现和隐式实现&#xff1a; 先定义一个接口&#xff0c;接口…

KotlinConf 2024:深入了解Kotlin Multiplatform (KMP)

KotlinConf 2024&#xff1a;深入了解Kotlin Multiplatform (KMP) 在近期的Google I/O大会上&#xff0c;我们推荐了Kotlin Multiplatform (KMP)用于跨移动、网页、服务器和桌面平台共享业务逻辑&#xff0c;并在Google Workspace中采用了KMP。紧接着&#xff0c;KotlinConf 2…

豆包浏览器插件会造成code标签内容无法正常显示

启用状态&#xff1a;页面的代码会显示不正常 禁用后&#xff0c;正常显示 害得我重置浏览器设置&#xff0c;一个个测试

CentOS7.9部署安装OpenGauss 5.0.2企业版

1、更新系统: yum update -y 2、更改主机名&#xff1a; hostnamectl set-hostname opendb01 3、关闭透明页&#xff1a; echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag# 加入开机自启动 echo …

微信小程序使用echarts

思路 五个tab公用一个柱状图组件切换tab以及切换时间改变数据&#xff0c;传入子组件&#xff0c;子组件监听数据重新更新点击柱状图显示具体数值每个时间点有两个柱子&#xff08;高压和低压&#xff09;&#xff0c;柱状图显示高压的最大值到最小值的范围除了血压其余只有一…