大家好,又见面了,我是你们的朋友全栈君。
本篇的内容,会介绍几个内容:单例,dll动态加载以及一些跨平台的处理。
1、单例:单例模式是一种使用广泛而又比较简单的设计模式,他的定义我就不多介绍了,大家上网一查就知道了,基本都能理解。在游戏开发中,会有很多单件,所以封装一个单例类供后面的开发使用。
本单例使用模板实现,代码如下:
[cpp] view plain copy print ?
- //singleton.h
- #ifndef _SINGLETON_H
- #define _SINGLETON_H
- namespace Blaze
- {
- template<class T>
- class Singleton
- {
- public:
- static T* instance()
- {
- if (!_instance)
- {
- _instance = new T;
- }
- return _instance;
- }
- protected:
- /// 使用保护构造是为了用户不能在栈上声明一个实例
- Singleton() {}
- private:
- static T* _instance; /// 实例静态指针
- };
- /// 静态实例指针初始化
- template <class T> T* Singleton<T>::_instance = NULL;
- } // namespace
- #endif //_SINGLETON_H
//singleton.h
#ifndef _SINGLETON_H
#define _SINGLETON_H
namespace Blaze
{
template<class T>
class Singleton
{
public:
static T* instance()
{
if (!_instance)
{
_instance = new T;
}
return _instance;
}
protected:
/// 使用保护构造是为了用户不能在栈上声明一个实例
Singleton() {}
private:
static T* _instance; /// 实例静态指针
};
/// 静态实例指针初始化
template <class T> T* Singleton<T>::_instance = NULL;
} // namespace
#endif //_SINGLETON_H
[cpp] view plain copy print ?
- //使用的时候只需要单件类继承此模板即可。
- class Test : public Singleton<Test >{…};
//使用的时候只需要单件类继承此模板即可。
class Test : public Singleton<Test >{...};
2、dll(so)动态加载
在开发网络游戏的过程中,现在已经不是能够单打独斗的年代了,一款游戏基本上不可能有一个人完成,因此分模块开发成为了必然,各自开发相关的模块,然后组合到一起。dll就是分模块开发的产物之一,它的加载有动态和静态之分,各有优势,但是由于服务器程序是需要运行在多个平台,而他们又各自有各自的加载方法,为了方便使用,因此我们队加载dll进行了封装。
实现使用模板,非常简单,代码如下
[cpp] view plain copy print ?
- // lib_def.h
- #ifndef __LIB_DEF_H_
- #define __LIB_DEF_H_
- namespace Blaze
- {
- // DLL对象创建辅助类
- template<const TCHAR*& szFileName>
- class DllApi
- {
- public:
- static BOOL Load()
- {
- if(!m_h) m_h = ::LoadLibrary(szFileName);
- return m_h != NULL;
- }
- static void Unload()
- {
- if(m_h) ::FreeLibrary(m_h);
- m_h = NULL;
- }
- protected:
- static HMODULE m_h;
- };
- template<const TCHAR*& szFileName> HMODULE DllApi<szFileName>::m_h;
- //库文件前后缀
- #ifdef WIN32
- #define __DLL_PREFIX _T(“”)
- #define __DLL_SUFFIX _T(“.dll”)
- #else
- #define __DLL_PREFIX _T(“lib”)
- #define __DLL_SUFFIX _T(“.so”)
- #endif
- // 声明DLL文件名常量
- #define DECLARE_DLL_FILE(module) extern “C” const TCHAR* module;
- // 定义DLL文件名常量
- #if !defined(_LIB) && !defined(_USE_STATIC_LIB)
- #define DEFINE_DLL_FILE(module) extern “C” const TCHAR* module = _T(“./”)””__DLL_PREFIX””_T(#module)””__DLL_SUFFIX;
- #else
- #define DEFINE_DLL_FILE(module)
- #endif
- }
- #endif
本例中使用了LoadLibrary,是windows的实现方法,在后面平台相关处理中,我会将linux的函数封装一下,和windows同名。此模板使用方法很简单:
[cpp] view plain copy print ?
- #if defined(_LIB) || defined(_USE_STATIC_LIB) // 静态库版本
- #ifndef _LUA_ENGINE_API
- #define _LUA_ENGINE_API IMPORT_API
- #pragma comment(lib, MAKE_LIB_NAME(LuaEngine))
- #endif
- _LUA_ENGINE_API ILuaEngine* GlobalLuaEngine();
- #else
- DECLARE_DLL_FILE(LuaEngine);
- class GlobalLuaEngine : public DllApi<LuaEngine>
- {
- typedef ILuaEngine* (*CREATE_PROC)();
- ILuaEngine* m_p;
- public:
- GlobalLuaEngine() : m_p(NULL)
- {
- Load();
- static CREATE_PROC func;
- if(func == NULL) func = (CREATE_PROC)::GetProcAddress(m_h, “GlobalLuaEngine”);
- if(func != NULL) m_p = func();
- }
- operator ILuaEngine* (){ return m_p; }
- ILuaEngine* operator ->(){ return m_p; }
- };
- #endif
#if defined(_LIB) || defined(_USE_STATIC_LIB) // 静态库版本 #ifndef _LUA_ENGINE_API #define _LUA_ENGINE_API IMPORT_API #pragma comment(lib, MAKE_LIB_NAME(LuaEngine)) #endif _LUA_ENGINE_API ILuaEngine* GlobalLuaEngine();#else DECLARE_DLL_FILE(LuaEngine); class GlobalLuaEngine : public DllApi<LuaEngine> { typedef ILuaEngine* (*CREATE_PROC)(); ILuaEngine* m_p; public: GlobalLuaEngine() : m_p(NULL) { Load(); static CREATE_PROC func; if(func == NULL) func = (CREATE_PROC)::GetProcAddress(m_h, "GlobalLuaEngine"); if(func != NULL) m_p = func(); } operator ILuaEngine* (){ return m_p; } ILuaEngine* operator ->(){ return m_p; } };#endif
如上面代码所示,LuaEngine是一个dll,我们在加载它的时候,使用了一个额外的类,在他的构造函数里面加载了共享库。而且在应用级上也与平台无关。
3、跨平台的若干处理
windows的处理相当简单,只是定义一些简单的宏。
[cpp] view plain copy print ?
- // gwindef.h : windows开发定义文件
- #ifndef __G_WIN_DEF_H_
- #define __G_WIN_DEF_H_
- #include <windows.h>
- #include <process.h>
- #include <tchar.h>
- #include <unknwn.h>
- #include <stdio.h>
- #include <stdlib.h>
- #define SYS_API WINAPI
- #define STD_CALL __stdcall
- #if !defined(_LIB)
- #define EXPORT_API extern “C” _declspec(dllexport)
- #else
- #define EXPORT_API extern “C”
- #endif
- #if !defined(_LIB) && !defined(_USE_STATIC_LIB)
- #define IMPORT_API extern “C” _declspec(dllimport)
- #else
- #define IMPORT_API extern “C”
- #endif
- #endif // ndef __G_WIN_DEF_H_
而为了开发的时候去除平台无关性,在linux的开发中,我们需要做一些包装,使其在开发过程中和window代码一致。 [cpp] view plain copy print ?
- // glindef.h : linux开发定义文件
- #ifndef __G_LIN_DEF_H_
- #define __G_LIN_DEF_H_
- //
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <wchar.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <semaphore.h>
- #include <errno.h>
- #include <sys/times.h>
- #include <time.h>
- #include <dlfcn.h>
- #include <sys/types.h>
- #include <linux/unistd.h>
- inline _syscall0(pid_t, gettid) /* Using syscall(2) may be preferable; see intro(2) */
- #ifdef UNICODE
- #define _T(str) L##str
- #else
- #define _T(str) str
- #endif
- #define TRUE 1
- #define FALSE 0
- #define MAX_PATH 256
- #define SYS_API
- #define STD_CALL
- #define EXPORT_API extern “C”
- #define IMPORT_API extern “C”
- /// HRESULT 常量定义
- typedef long HRESULT;
- enum HResult
- {
- S_OK = ((HRESULT)0x00000000), /**< 成功,值为0 */
- S_FALSE = ((HRESULT)0x00000001), /**< 成功,但值为1 */
- E_FAIL = _HRESULT_TYPEDEF_(0x80004005), /**< 未定义错误 */
- E_NOTIMPL = _HRESULT_TYPEDEF_(0x80004001), /**< 接口未实现 */
- E_OUTOFMEMORY = _HRESULT_TYPEDEF_(0x8007000E), /**< 内存不足 */
- E_INVALIDARG = _HRESULT_TYPEDEF_(0x80070057), /**< 无效参数 */
- E_NOINTERFACE = _HRESULT_TYPEDEF_(0x80004002), /**< 接口不存在 */
- E_POINTER = _HRESULT_TYPEDEF_(0x80004003), /**< 无效指针 */
- E_HANDLE = _HRESULT_TYPEDEF_(0x80070006), /**< 无效句柄 */
- E_ABORT = _HRESULT_TYPEDEF_(0x80004004), /**< 操作被取消 */
- E_ACCESSDENIED = _HRESULT_TYPEDEF_(0x80070005), /**< 访问拒绝 */
- E_PENDING = _HRESULT_TYPEDEF_(0x8000000A), /**< 操作被挂起 */
- E_UNEXPECTED = _HRESULT_TYPEDEF_(0x8000FFFF) /**< 未预料的错误 */
- };
- /// 判定 HRESULT 值是否为成功值
- #define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
- /// 判定 HRESULT 值是否为失败值
- #define FAILED(Status) ((HRESULT)(Status) < 0)
- /// GUID 类型定义
- /**
- 要定义 GUID 常量请使用 GUID 专门的生成工具(比如 VS 携带的 guidgen.exe 程序)来生成,
- 以确保其唯一性。
- 接口 ID(IID), 类 ID(CLSID)均为 GUID 的别名*/
- struct GUID
- {
- unsigned long Data1;
- unsigned short Data2;
- unsigned short Data3;
- unsigned char Data4[8];
- };
- typedef GUID IID;
- typedef GUID CLSID;
- #define REFGUID const GUID&
- #define REFIID const IID&
- #define REFCLSID const CLSID&
- /// 判断两个 GUID 是否相等(内联版)
- inline BOOL InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2)
- {
- return ((long*)&rguid1)[0] == ((long*)&rguid2)[0] &&
- ((long*)&rguid1)[1] == ((long*)&rguid2)[1] &&
- ((long*)&rguid1)[2] == ((long*)&rguid2)[2] &&
- ((long*)&rguid1)[3] == ((long*)&rguid2)[3];
- }
- /// 判断两个 GUID 是否相等
- inline BOOL IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
- {
- return !memcmp(&rguid1, &rguid2, sizeof(GUID));
- }
- #define CopyMemory(dest, src, len) memcpy((dest), (src),(len))
- #define ZeroMemory(dest, len) memset((dest), 0, (len))
- #define FillMemory(dest, len, value) memset((dest), value, (len))
- #define GetCurrentThreadId gettid
- #define OutputDebugString(str) tprintf(_T(“%s”), str)
- #define LoadLibrary(file) dlopen(file, RTLD_NOW)
- #define FreeLibrary dlclose
- #define GetProcAddress dlsym
- inline int GetLastError()
- {
- return errno;
- }
- inline DWORD GetTickCount()
- {
- static int clkTck = 0;
- if(clkTck == 0) clkTck = 1000 / ::sysconf(_SC_CLK_TCK);
- return (DWORD)::times(NULL) * clkTck; // 不能溢出
- }
- inline void Sleep(DWORD ms)
- {
- struct timespec req, rem;
- req.tv_sec = ms / 1000; req.tv_nsec = (ms % 1000) * 1000000;
- while(::nanosleep(&req, &rem) && ::GetLastError() == EINTR) req = rem;
- }
- inline long InterlockedIncrement(long volatile* v)
- {
- long src = 1;
- /* Modern 486 processor */
- __asm__ __volatile__(
- “lock xaddl %0, %1;”
- :”=r”(src), “=m”(*v)
- :”0″(src));
- return src 1;
- }
- inline long InterlockedDecrement(long volatile* v)
- {
- long src = -1;
- /* Modern 486 processor */
- __asm__ __volatile__(
- “lock xaddl %0, %1;”
- :”=r”(src), “=m”(*v)
- :”0″(src));
- return src – 1;
- }
- #define stricmp strcasecmp
- #include <ctype.h>
- inline void strupr(char *s)
- {
- while (*s) {
- *s = toupper((unsigned char) *s);
- s ;
- }
- }
- inline void strlwr(char *s)
- {
- while (*s) {
- *s = tolower((unsigned char) *s);
- s ;
- }
- }
- #endif // ndef __G_LIN_DEF_H_
// glindef.h : linux开发定义文件
#ifndef __G_LIN_DEF_H_
#define __G_LIN_DEF_H_
//
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <sys/times.h>
#include <time.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <linux/unistd.h>
inline _syscall0(pid_t, gettid) /* Using syscall(2) may be preferable; see intro(2) */
#ifdef UNICODE
#define _T(str) L##str
#else
#define _T(str) str
#endif
#define TRUE 1
#define FALSE 0
#define MAX_PATH 256
#define SYS_API
#define STD_CALL
#define EXPORT_API extern "C"
#define IMPORT_API extern "C"
/// HRESULT 常量定义
typedef long HRESULT;
enum HResult
{
S_OK = ((HRESULT)0x00000000), /**< 成功,值为0 */
S_FALSE = ((HRESULT)0x00000001), /**< 成功,但值为1 */
E_FAIL = _HRESULT_TYPEDEF_(0x80004005), /**< 未定义错误 */
E_NOTIMPL = _HRESULT_TYPEDEF_(0x80004001), /**< 接口未实现 */
E_OUTOFMEMORY = _HRESULT_TYPEDEF_(0x8007000E), /**< 内存不足 */
E_INVALIDARG = _HRESULT_TYPEDEF_(0x80070057), /**< 无效参数 */
E_NOINTERFACE = _HRESULT_TYPEDEF_(0x80004002), /**< 接口不存在 */
E_POINTER = _HRESULT_TYPEDEF_(0x80004003), /**< 无效指针 */
E_HANDLE = _HRESULT_TYPEDEF_(0x80070006), /**< 无效句柄 */
E_ABORT = _HRESULT_TYPEDEF_(0x80004004), /**< 操作被取消 */
E_ACCESSDENIED = _HRESULT_TYPEDEF_(0x80070005), /**< 访问拒绝 */
E_PENDING = _HRESULT_TYPEDEF_(0x8000000A), /**< 操作被挂起 */
E_UNEXPECTED = _HRESULT_TYPEDEF_(0x8000FFFF) /**< 未预料的错误 */
};
/// 判定 HRESULT 值是否为成功值
#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
/// 判定 HRESULT 值是否为失败值
#define FAILED(Status) ((HRESULT)(Status) < 0)
/// GUID 类型定义
/**
要定义 GUID 常量请使用 GUID 专门的生成工具(比如 VS 携带的 guidgen.exe 程序)来生成,
以确保其唯一性。
接口 ID(IID), 类 ID(CLSID)均为 GUID 的别名*/
struct GUID
{
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
};
typedef GUID IID;
typedef GUID CLSID;
#define REFGUID const GUID&
#define REFIID const IID&
#define REFCLSID const CLSID&
/// 判断两个 GUID 是否相等(内联版)
inline BOOL InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
return ((long*)&rguid1)[0] == ((long*)&rguid2)[0] &&
((long*)&rguid1)[1] == ((long*)&rguid2)[1] &&
((long*)&rguid1)[2] == ((long*)&rguid2)[2] &&
((long*)&rguid1)[3] == ((long*)&rguid2)[3];
}
/// 判断两个 GUID 是否相等
inline BOOL IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
return !memcmp(&rguid1, &rguid2, sizeof(GUID));
}
#define CopyMemory(dest, src, len) memcpy((dest), (src),(len))
#define ZeroMemory(dest, len) memset((dest), 0, (len))
#define FillMemory(dest, len, value) memset((dest), value, (len))
#define GetCurrentThreadId gettid
#define OutputDebugString(str) tprintf(_T("%s"), str)
#define LoadLibrary(file) dlopen(file, RTLD_NOW)
#define FreeLibrary dlclose
#define GetProcAddress dlsym
inline int GetLastError()
{
return errno;
}
inline DWORD GetTickCount()
{
static int clkTck = 0;
if(clkTck == 0) clkTck = 1000 / ::sysconf(_SC_CLK_TCK);
return (DWORD)::times(NULL) * clkTck; // 不能溢出
}
inline void Sleep(DWORD ms)
{
struct timespec req, rem;
req.tv_sec = ms / 1000; req.tv_nsec = (ms % 1000) * 1000000;
while(::nanosleep(&req, &rem) && ::GetLastError() == EINTR) req = rem;
}
inline long InterlockedIncrement(long volatile* v)
{
long src = 1;
/* Modern 486 processor */
__asm__ __volatile__(
"lock xaddl %0, %1;"
:"=r"(src), "=m"(*v)
:"0"(src));
return src 1;
}
inline long InterlockedDecrement(long volatile* v)
{
long src = -1;
/* Modern 486 processor */
__asm__ __volatile__(
"lock xaddl %0, %1;"
:"=r"(src), "=m"(*v)
:"0"(src));
return src - 1;
}
#define stricmp strcasecmp
#include <ctype.h>
inline void strupr(char *s)
{
while (*s) {
*s = toupper((unsigned char) *s);
s ;
}
}
inline void strlwr(char *s)
{
while (*s) {
*s = tolower((unsigned char) *s);
s ;
}
}
#endif // ndef __G_LIN_DEF_H_
代码都比较简单,我也不对这些做详细的解析,功能就是对一些常用函数改装成windows相关函数的名字。如果在开发中遇到了其他的情况,也可以加到此文件中,以方便应用开发。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/125579.html原文链接:https://javaforall.cn