我最近决定将一些函数导出到静态库(.lib)。我还决定不向用户提供完整的头文件。我保留了私有和受保护的变量和方法,因为最终用户不应该使用它们,也不必包含类声明的其他标头。
出乎意料的是,在创建导出到静态库的类的实例时,我遇到了堆损坏错误。
这是我原来的头文件:
// Original Header File
class CODBCHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
private:
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
};
然后我决定取出私有变量,以便我的.lib用户不会滥用它们,也不必包含不必要的SQL头文件:
// Minimized Header File
class CODBCHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
};
我注意到sizeof
Operation会根据调用的位置返回不同的值。
在.lib中调用:
int size = sizeof(CODBCHelper);
// size is 12
在链接项目中调用:
int size = sizeof(CODBCHelper);
// size is 1
在我的链接项目中执行以下代码会导致堆损坏(这可能是因为大小计算错误):
CODBCHelper* helper = new CODBCHelper;
做类似
的事情class CODBCHelper
{
[...]
private:
char padding[12];
}
可以解决问题,但我认为它的行为非常糟糕,根本无法维持。
那么有没有办法告诉编译器真正的Object(来自链接库)有多大?或者是否有任何简单的方法可以隐藏用户不需要的头文件中的声明?
答案 0 :(得分:2)
我不知道&#34;隐藏不重要的成员&#34;已连接到从类定义中删除它们。
我想,您希望从代码中消除不必要的依赖项。这是一种很好的技术 - 它减少了编译时间,使您的代码在不同版本之间更容易移植等等。
问题是,你完全改变了你的课程。如果它被设计为有三个私人成员:
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
你不能只是删除它们。这不是&#34;隐藏实现细节&#34;装置
或者是否有任何简单的方法可以隐藏用户不需要的头文件中的声明?
您想要的是使用PIMPL Idiom:
//Minimized header file
class CODBCHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
private:
struct InternalData;
InternalData* m_internal_data;
};
然后,在.cpp
文件中:
struct CODBCHelper::InternalData
{
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
};
现在,您将实施更改为分别使用m_internal_data
而不是每个组件。如果您的软件将被更新,这将特别有利可图 - 它禁止客户创建代码,这取决于您的类型的实现细节。
您可能还想阅读this answer的 2。和/或 4。。
答案 1 :(得分:1)
您可以公开接口而不是类+工厂类。这样,您的用户就无法看到实际课程的结构,一切正常。
例如,您的用户可以获得此信息:
class ICODBCHelper
{
public:
virtual ~ICODBCHelper();
public:
virtual std::vector<UserData> getUserInformation();
};
class MyFactory
{
public:
ICODBHelper *CreateCODBHelper();
}
你实现了这个:
class CODBCHelper : public ICODBHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
private:
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
};
答案 2 :(得分:0)
使用纯虚方法创建一个公共的抽象类,没有数据。然后创建一个工厂/访问器来实例化/访问库代码中的实际对象,该实际对象实际上是抽象类的派生/具体类。