Reputation: 3198
I recently decided to export some of my functions to a static library (.lib). I also decided not to give the complete header files to the Users. I kept private and protected variables and methods out of it, as the end-users should not use them and should not have to include other headers for Class declarations.
Unexpectedly I ran into heap-corruption errors when creating instances of the Classes which I exported to the static lib.
This is my original header file:
// Original Header File
class CODBCHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
private:
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
};
Then I decided to take the private variables out, so that users of my .lib do not abuse them and do not have to include unnecessary SQL Header files:
// Minimized Header File
class CODBCHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
};
I noticed that the sizeof
Operation returns different values depending from where it is called.
Called in the .lib:
int size = sizeof(CODBCHelper);
// size is 12
Called in the linking project:
int size = sizeof(CODBCHelper);
// size is 1
Doing the following code in my linking project then causes a heap corruption (which happens probably because of wrong size calculations):
CODBCHelper* helper = new CODBCHelper;
Doing something like
class CODBCHelper
{
[...]
private:
char padding[12];
}
would solve the problem, but i think its really bad behavior and not maintainable at all.
So is there any way to tell the compiler how big the real Object (from the linked library) is going to be? Or is there any easy way of hiding declarations in header files that are not needed by users?
Upvotes: 1
Views: 600
Reputation: 12058
I don't see how "hiding unimportant members" is connected to removing them from class definition.
I guess, that you wanted to eliminate unnecessary dependencies from your code. This is a good technique - it reduces compilation time, makes your code more portable between different versions and much more.
The thing is, that you changed your class completely. If it was designed to have three private members:
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
you cannot just remove them. This is not what "hiding implementation details" means.
Or is there any easy way of hiding declarations in header files that are not needed by users?
What you want is to use PIMPL Idiom:
//Minimized header file
class CODBCHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
private:
struct InternalData;
InternalData* m_internal_data;
};
Then, in your .cpp
file:
struct CODBCHelper::InternalData
{
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
};
Now you change your implementation to use m_internal_data
instead of each component separately. This is especially profitable if your software will be updated - it forbids clients to create code, that depends on implementation details of your types.
You may also want to read point 2. and/or 4. of this answer.
Upvotes: 2
Reputation: 46323
You could expose interfaces instead of classes + a factory class. That way your users don't see the construct of your actual classes and everything works fine.
For example, your users get this:
class ICODBCHelper
{
public:
virtual ~ICODBCHelper();
public:
virtual std::vector<UserData> getUserInformation();
};
class MyFactory
{
public:
ICODBHelper *CreateCODBHelper();
}
and you implement this:
class CODBCHelper : public ICODBHelper
{
public:
CODBCHelper();
virtual ~CODBCHelper();
public:
std::vector<UserData> getUserInformation();
private:
SQLHENV m_henv;
SQLHDBC m_hdbc;
SQLHSTMT m_hstmt;
};
Upvotes: 1
Reputation: 3156
Create an abstract class that is public with pure virtual methods, no data. Then create a factory/accessor to instantiate/access the actual object in your library code that is actually a derived/concrete class of the abstract class.
Upvotes: 0