如何解决VC中的警告warning C4251 needs to have dll-interface

本文探讨了在DLL导出类中使用模板类时遇到的警告C4251问题,并提供了四种解决方案,包括忽略警告、修改为指针、导出模板依赖及使用Impl模式。
部署运行你感兴趣的模型镜像

原文地址:http://hi.baidu.com/_%E2d_%B7%B3_%DE%B2%C2%D2/blog/item/a69368fa45782715a9d311c1.html

 

    
这通常是由于以数据成员方式在DLL导出类中使用了模板类造成的。比如:
#include <iostream>
#include <vector>
using namespace std;

class __declspec( dllexport ) Test
{
public:
std::vector<int> m_objCon;
};

int main()
{


return 0;
}

这会导致这个警告:
warning C4251: “Test::m_objCon”: class“std::vector<_Ty>”需要有 dll 接口由 class“Test”的客户端使用
1>        with
1>        [
1>            _Ty=int
1>        ]
这个问题主要要描述的是不同的地方的vector的实现可能不一样所造成的问题。所以我们应该将其导出。有很多方法可以解决这个问题的。

第一种: 无视它或者#pragma warnind( disable: 4251 )
第二种:将该数据改为指针方式:
class __declspec( dllexport ) Test
{
public:
std::vector<int>* m_objCon;
};
然后在构造函数和析构函数中分别初始化和释放它。
第三种:
将该模板类及其依赖类导出。
#include <iostream>
#include <vector>
using namespace std;

class __declspec( dllexport ) Test
{
public:
template  class __declspec( dllexport ) std::allocator<int>;
template  class __declspec( dllexport ) std::vector<int, std::allocator<int> >;
public:

std::vector<int> m_objCon;
};

int main()
{


return 0;
}
这种方法要注意的是必须要把要导出模板类的模板数据成员一并导出。有点类似于显式实例化。比如说你要导出boost::shared_ptr就还必须将其 依赖的shared_count一并导出。导出map还需要导出对应pair等等。很麻烦啦~所以我们还是选择第四种吧。

第四种:Impl。
#include <iostream>
#include <vector>
using namespace std;

// 这些放到.h中
class Test_imp;
class __declspec( dllexport ) Test
{
// 构造函数中初始化 析构中释放m_pImp;
void test();
public:
Test_imp* m_pImp;
};

// 这个类放到cpp中去
class  Test_imp
{
public:
void test(){}
std::vector<int> m_objCon;
};

// 放到cpp中
void Test::test()
{
m_pImp->test();
}

int main()
{


return 0;
}

个人推荐第二种和第四种,反对第一种。毕竟掩耳盗铃不是好习惯~~
第四种除了可以解决上面的问题之外还可以隐藏代码,当然多了一个桥接的过程。关于这个东西可以看看我08年的时候写的一篇垃圾文章,也许有帮助:这 里
那时候比现在还菜,所以乱七八糟的,凑合看看吧~ (比 如说导出类的时候每个函数都去加_declspec(dllexport),那是一个悲剧,不要学哦~)

您可能感兴趣的与本文相关的镜像

Dify

Dify

AI应用
Agent编排

Dify 是一款开源的大语言模型(LLM)应用开发平台,它结合了 后端即服务(Backend as a Service) 和LLMOps 的理念,让开发者能快速、高效地构建和部署生产级的生成式AI应用。 它提供了包含模型兼容支持、Prompt 编排界面、RAG 引擎、Agent 框架、工作流编排等核心技术栈,并且提供了易用的界面和API,让技术和非技术人员都能参与到AI应用的开发过程中

在window10安装vs2013编译,调试程序 给出解释并修正方案 下面是vs2013出现以下错误代码 warning C4251: “VTTestManagerBS::m_vtTestMap”: class“std::map<std::string,VTTestManagerBS::VTTestItem *,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>”需要有 dll 接口class“VTTestManagerBS”的客户端使用 1> with 1> [ 1> _Kty=std::string 1> , _Ty=VTTestManagerBS::VTTestItem * 1> ] 1>d:\rxxq-project\server_src _2013\server\code\sourcecode\src\foundation\VTTest.h(122): warning C4251: “VTTestManagerBS::m_vtTestList”: class“std::vector<VTTestManagerBS::VTTestItem *,std::allocator<_Ty>>”需要有 dll 接口class“VTTestManagerBS”的客户端使用 1> with 1> [ 1> _Ty=VTTestManagerBS::VTTestItem * 1> ] 1>d:\rxxq-project\server_src _2013\server\code\sourcecode\src\foundation\VTTest.h(124): warning C4251: “VTTestManagerBS::m_reportString”: class“std::basic_string<char,std::char_traits<char>,std::allocator<char>>”需要有 dll 接口class“VTTestManagerBS”的客户端使用 1>d:\rxxq-project\server_src _2013\server\code\sourcecode\src\foundation\VTTest.h(132): warning C4251: “VTTestManagerBS::m_reportPath”: class“std::basic_string<char,std::char_traits<char>,std::allocator<char>>”需要有 dll 接口class“VTTestManagerBS”的客户端使用 1>d:\rxxq-project\server_src _2013\server\code\sourcecode\src\foundation\VTTest.h(159): warning C4251: “VTTestOP::m_testName”: class“std::basic_string<char,std::char_traits<char>,std::allocator<char>>”需要有 dll 接口class“VTTestOP”的客户端使用 程序原代码: #ifndef LOG_MGR_SINGLETON_H #define LOG_MGR_SINGLETON_H 1 //资源管理类 #include "../Memory/FreeList.h" #include "../TObjectPool.h" #include <memory> // 添加智能指针支持 class LogManagerImpl; // 前置声明 class LogStream; //!日志记录的条目信息结构体 struct _Foundation_Export_ LOG_ITEM { public: ////!操纵控制块 表的互斥变量 static Thread::RecMutex m_mutex; _Def_Pool_Factory_(LOG_ITEM); //!日志条目配置信息 enum ENLOGITEMCONFIG { //!最大日志长度 enMaxLogItemSize = 1024, //!最大名字长度 enMaxLogNameSize = 32, }; char m_typeName[enMaxLogNameSize+1]; char m_szDesc[enMaxLogItemSize+1]; unsigned int m_nNumber; public: //结构体赋值 int SetValue(const std::string& strType, const char* pszDesc, const unsigned int nNumber) { size_t cpySize = enMaxLogNameSize > strType.size() ? strType.size() : enMaxLogNameSize; memcpy(m_typeName,strType.c_str(),cpySize); m_typeName[cpySize] = 0; m_nNumber = sizeof(m_szDesc); if (m_nNumber > nNumber) { m_nNumber = nNumber; } memcpy(m_szDesc, pszDesc, m_nNumber); return true; }; LOG_ITEM& operator = (const LOG_ITEM& item) { memcpy(m_typeName,item.m_typeName,sizeof(m_typeName)); m_nNumber = sizeof(item.m_szDesc); if (m_nNumber > item.m_nNumber) { m_nNumber = item.m_nNumber; } memcpy(m_szDesc, item.m_szDesc, m_nNumber); return *this; } LOG_ITEM& operator = (const LOG_ITEM* pItem) { memcpy(m_typeName,pItem->m_typeName,sizeof(m_typeName)); m_nNumber = pItem->m_nNumber; memcpy(m_szDesc, pItem->m_szDesc, m_nNumber); return *this; } void Reset(void) { } }; /** * @brief Log性能参数记录 */ class _Foundation_Export_ LogPerfData { public: LogPerfData(void) :m_logTotalCount(0) { } //!总共记录的条目数量 unsigned int m_logTotalCount; protected: private: }; /** *日志记录,单件模式 */ class _Foundation_Export_ LogMgrSingleton { _Singleton_Decl(LogMgrSingleton); public: // Constructor LogMgrSingleton(); // Destructor virtual ~LogMgrSingleton(); //!性能参数记录 LogPerfData m_perf; //日志有关操作 public: //!注册一个日志类型 bool RegisterLog(std::string strType); //!获得LogItem,以便于外部直接改写Item中的数据,避免一次拷贝 LOG_ITEM* GetLogItem(void); //!直接报告LogItem int Report(LOG_ITEM* item); //!日志输出,放入列表 int Report(const std::string& strType, const char* pszDesc, const int lNumber); //!日志输出, int ReportEx(const std::string& strType, char* pszDesc, int lNumber); //!线程调用的函数 static void WriteLog(void* ptr); //!具体的处理Log的函数 void WriteLogEx(); //!依据注册名,查找log流 LogStream* LookupStreamByName(const std::string& name); //输出流有关操作 public: //!压入一个stream,以后创建流就用这个创建 void PushStream(LogStream* stream); //!获得一个预先压入的stream LogStream* CreateStream(const std::string& n); //!弹出一个stream LogStream* PopStream(void); //创建文件有关操作 private: //!创建logs文件夹 int CreateLogsDirectory(void* pContext); //!创建当前日期文件夹 int CreateDateDirectory(void* pContext); //!获得当前日期 int GetCurrentDate(char* pszReturn, const int nLength); //!文件是否存在 int IsFileExist(std::string& strPath); private: //!从日志队列m_queLogList中获得第一个Log. LOG_ITEM* GetFrontLogData(void); private: //存放日志文件的句柄 std::map<std::string, FILE*> m_vecLogFileHandle; std::map<std::string, LogStream*> m_vecLogStream; //std::unique_ptr<LogManagerImpl> pImpl; // Pimpl惯用法 //File Handle FILE* m_hFile; //logs文件夹 std::string m_strLogsPath; std::stack<LogStream*> _streamStack; AG_Time m_AG_Time; private: Thread::BaseThread* m_LogThread; ////!操纵控制块 表的互斥变量 Thread::RecMutex m_mutex; //!开始log的信号量 Thread::Semaphore m_sem; private: //!日志结构体 LOG_ITEM m_LogItem; //!存放所有日志的线性链表(目前使用queue代替) std::queue<LOG_ITEM*> m_queLogList; //!下面创建的内存对象,最好能放到 private: //!创建玩家对象 LOG_ITEM* CreateLogItem(void); //!删除玩家对象 void FreeLogItem(LOG_ITEM* pLogItem); private: //预存放日志的内存分配 gems::FreeList< LOG_ITEM, gems::CompactableChunkPolicy<LOG_ITEM>, gems::ConstantChunkSizeGrowthPolicy<LOG_ITEM, 1024> > m_logMemoryList; }; //! #define LOG_REPORT_PUSHSTREAM(ptr) LogMgrSingleton::Instance()->PushStream(ptr) #define LOG_REPORT_POPSTREAM() LogMgrSingleton::Instance()->PopStream() //! #define LOG_REPORT_REGISTER(path) LogMgrSingleton::Instance()->RegisterLog(path) #define LOG_REPORT_EX(path, desc, num) LogMgrSingleton::Instance()->Report(path, desc, num) #define LOG_REPORT_LOOKUP(name) LogMgrSingleton::Instance()->LookupStreamByName(name) extern "C" { void _Foundation_Export_ _LOG_REPORT_OUTPUT_(const char* pszType,const char* pszString,...); #define LOG_REPORT_OUTPUT void _Foundation_Export_ _Server_LOG_File_(const char* pszType,const char* pszString,...); void _Foundation_Export_ debugOutputString(const char* pszString,...); //void _Foundation_Export_ LOG_REPORT_OUTPUT2( ); } #endif
最新发布
11-08
在window10安装vs2013编译,调试程序 出现以下错误代码 warning C4251: “LogManagerSingleton::_streamStack”: class“std::stack<LogStream *,std::deque<_Ty,std::allocator<_Ty>>>”需要有 dll 接口class“LogManagerSingleton”的客户端使用 给出解释并修正方案 下面是代码: // Copyright (C) 1991 - 1999 Rational Software Corporation #if defined (_MSC_VER) && (_MSC_VER >= 1000) #pragma once #endif #ifndef _INC_LOGMANAGERSINGLETON_4112E32B0157_INCLUDED #define _INC_LOGMANAGERSINGLETON_4112E32B0157_INCLUDED #include <stack> //定义Enable操作是否可以Register新的LOG //#define _ENABLE_WITH_NEW class LogSwitchBox; class LogLeaf; class LogStream; class LogStreamSimpleFile; /** *日志记录管理者,单件模式 */ class _Foundation_Export_ LogManagerSingleton { public: LogSwitchBox* GetRoot() const; // Destructor virtual ~LogManagerSingleton(); bool RegisterLog(const std::string path ); //!压入一个stream,以后创建流就用这个创建 void PushStream(LogStream* stream); //!弹出一个stream LogStream* PopStream(void); static LogManagerSingleton* getInstance(); static void Cleanup(void); protected: LogStream* CreateStream(const std::string& name,const std::string& fullPath); // Constructor LogManagerSingleton(); LogSwitchBox* _root; std::stack<LogStream*> _streamStack; private: static LogManagerSingleton* uniqueInstance; public: int Report(const std::string path,std::string desc); int Report(const std::string path,std::string desc,long num); // 设置节点或者叶子的状态 void Enable(const std::string path,bool enable); }; // #define LOG_PUSHSTREAM(ptr) LogManagerSingleton::getInstance()->PushStream(ptr) #define LOG_POPSTREAM() LogManagerSingleton::getInstance()->PopStream() #define LOG_REPORTNUM(path,desc,num) LogManagerSingleton::getInstance()->Report(path,desc,num) #define LOG_REPORT(path,desc) LogManagerSingleton::getInstance()->Report(path,desc) #define LOG_ENABLE(path,enable) LogManagerSingleton::getInstance()->Enable(path,enable) #define LOG_REGISTER(path) LogManagerSingleton::getInstance()->RegisterLog(path) #define LOG_CLEANUP() do{/*delete LogManagerSingleton::getInstance()*/LogManagerSingleton::Cleanup();}while(0) extern "C" { void _Foundation_Export_ LOG_REPORTVAR(const char* path,const char* pszString,...); void _Foundation_Export_ LOG_ASSERT(bool exp,const char* pszString,...); } extern "C" { void _Foundation_Export_ LOG_DEBUG_REPORT(const char* path,const char* pszString,...); } #endif /* _INC_LOGMANAGERSINGLETON_4112E32B0157_INCLUDED */ // Copyright (C) 1991 - 1999 Rational Software Corporation #include "stdafx.h" #include "LogManagerSingleton.h" #include "LogSwitchBox.h" #include "LogLeaf.h" #include "LogStream.h" #include "LogStreamSimpleFile.h" LogManagerSingleton* LogManagerSingleton::uniqueInstance=0; LogStream* LogManagerSingleton::CreateStream(const std::string& name,const std::string& fullPath) { if (_streamStack.size() > 0) { LogStream* stream = _streamStack.top(); return stream->CreateStream(name,fullPath); } return new LogStreamSimpleFile(name,fullPath); } bool LogManagerSingleton::RegisterLog(const std::string path) { // TODO: Add your specialized code here. std::string opPath = path; if(opPath[0] != '/') return false; std::string fullPath=opPath; std::string childName; std::string tempStr=opPath; LogSwitchBox* parent=_root,*child=0; int offset=0,offsetEnd=0; opPath=opPath.c_str()+1;//去掉'/' for(;;) { offset=static_cast<int>(opPath.find('/')); if(-1 != offset) {//非叶子 childName=""; childName.append(opPath.c_str(),offset); opPath=opPath.c_str()+offset+1;//去掉childName/ child=(LogSwitchBox*)(parent->FindChildByName(childName)); if(!child) { child=new LogSwitchBox(childName); parent->AddChild(child); } parent=child; } else {//叶子 //childName="" childName=opPath; LogCtrl* leaf=parent->FindChildByName(childName); if(!leaf) {//无同名叶子 LogStream* stream=CreateStream(childName,fullPath); leaf=new LogLeaf(childName,stream); parent->AddChild(leaf); return true; } else { LogStream* stream=CreateStream(childName,fullPath); ((LogLeaf*)leaf)->ChangeStream(stream); } return true; } if(opPath.empty()) return true; } } LogManagerSingleton* LogManagerSingleton::getInstance() { // TODO: Add your specialized code here. // NOTE: Requires a correct return value to compile. if(uniqueInstance) { return uniqueInstance; } else { uniqueInstance=new LogManagerSingleton; return uniqueInstance; } } void LogManagerSingleton::Cleanup(void) { if (uniqueInstance) { delete uniqueInstance; uniqueInstance = 0; } } LogManagerSingleton::LogManagerSingleton() : _root(0) { // ToDo: Add your specialized code here and/or call the base class _root=new LogSwitchBox(std::string("/")); } LogManagerSingleton::~LogManagerSingleton() { // ToDo: Add your specialized code here and/or call the base class _root->Flush(); delete _root; _root=0; LogStream* stream = 0; while (!_streamStack.empty()) { stream = _streamStack.top(); stream->ReleaseStream(); _streamStack.pop(); } } LogSwitchBox* LogManagerSingleton::GetRoot() const { return _root; } int LogManagerSingleton::Report(const std::string path,std::string desc) { if(_root) _root->Report(path,desc); return 0; } int LogManagerSingleton::Report(const std::string path, std::string desc,long num) { char sz[20]={""}; _snprintf(sz,20,"%d",num); desc.append(sz); if(_root) _root->Report(path,desc); return 0; } // 设置节点或者叶子的状态 void LogManagerSingleton::Enable(const std::string path,bool enable) { std::string opPath = path; std::string tempStr,childName; int offsetStart=0,offsetEnd=0; LogSwitchBox* parent=_root; LogCtrl* child=0; for(;;) { if(opPath.empty()) return; offsetStart=static_cast<int>(opPath.find('/')); tempStr=opPath.c_str()+1;//去掉第一个'/' offsetEnd=static_cast<int>(tempStr.find('/')); if(offsetStart == -1 || -1 == offsetEnd) {//叶子 第2中情况是opPath为"/xxxxx",也就是根的叶子 if(offsetStart == -1) childName=opPath; else childName=opPath.c_str()+1; child=parent->FindChildByName(childName); if(!child) { #ifdef _ENABLE_WITH_NEW LogStream* stream=new LogStreamSimpleFile(childName); child=new LogLeaf(childName,stream); parent->AddChild(child); #else #ifdef _WIN32 MessageBox(0,opPath.c_str(),"LOG PATH NOT FOUND",MB_OK); #endif return; #endif } child->Enable(enable); return; } else {//非叶子 childName=""; childName.append(tempStr.c_str(),offsetEnd); child=parent->FindChildByName(childName); if(!child) { #ifdef _ENABLE_WITH_NEW child=new LogSwitchBox(childName); parent->AddChild(child); #else return; #endif } opPath=tempStr.c_str()+1+offsetEnd; parent=(LogSwitchBox*)child; continue; } } } void LogManagerSingleton::PushStream(LogStream* stream) { _streamStack.push(stream); } LogStream* LogManagerSingleton::PopStream(void) { if (_streamStack.size() > 0) { LogStream* stream = _streamStack.top(); _streamStack.pop(); return stream; } return 0; } void LOG_REPORTVAR(const char* path,const char* pszString,...) { char szDesc[1024*32]; //修改Log长度为1024 va_list va; va_start(va, pszString); #ifdef _WIN32 StringCbVPrintf(szDesc, 1024*32, pszString, va); //修改Log长度为1024 #else wvsprintf( szDesc, pszString, va ); #endif va_end(va); LOG_REPORT(path, szDesc); } void LOG_ASSERT(bool exp,const char* pszString,...) { if (!exp) { char szDesc[256]; //修改Log长度为1024 va_list va; va_start(va, pszString); #ifdef _WIN32 StringCbVPrintf(szDesc, 256, pszString, va); //修改Log长度为1024 #else wvsprintf( szDesc, pszString, va ); #endif va_end(va); //MessageBox(0,szDesc,"Assert",MB_OK); //LOG_REPORT("/Foundation/Assert", szDesc); } } #ifdef _DEBUG void LOG_DEBUG_REPORT(const char* path,const char* pszString,...) { char szDesc[1024*32]; va_list va; va_start( va, pszString ); #ifdef _WIN32 StringCbVPrintf( szDesc,1024*32, pszString, va ); #else wvsprintf( szDesc, pszString, va ); #endif va_end( va ); LOG_REPORT(path,szDesc); } #else void LOG_DEBUG_REPORT(const char* path,const char* pszString,...) { } #endif
11-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值