23:47 

Трюк 0x0009 — Deep Private

Куб 0
Иногда разработчику класса нужно скрыть от пользователя некоторые особенности реализации интерфейса. Речь идет о секции private, в которой обычно размещаются переменные класса и методы, предназначенные сугубо для внутреннего использования. Пользователю вовсе необязательно видеть секцию private, особенно, если реализация класса находится внутри скомпилированной библиотеки .dll, а в руках пользователя лишь заголовочный файл.
Предполжим, есть заголовочный файл следующего вида.

//------------------------------------------------------------
class A {
public:
A(char *, int);
~A();
private:
int m_Value;
char *m_Str;
static int g_Instances;
void init();
};
//------------------------------------------------------------


и файл с реализацией класса:

//------------------------------------------------------------
int A::g_Instances=0;
A::A(char *Str, int Val) {
m_Value=Val;
m_Str=Str;
init();
}
void A::~A() {}
void A::init() {
g_Instances++;
}
//------------------------------------------------------------


Существует достаточно простое решение для минимизации содержимого секции private (до двух строчек).
Заголовочный файл оформляется следующим образом:

//------------------------------------------------------------
class A {
public:
A(char *, int);
~A();
private:
class InternalData;
InternalData *m_IData;
};
//------------------------------------------------------------


Вот и всё. Объявляется новый класс, и создается переменная-указатель. Для ее создания компилятору не нужна реализация класса InternalData.
Теперь как же выглядит файл с реализациями классов A и InternalData? Во-первых, добавилось тело класса InternalData, и, во-вторых, доступ к полям private осуществляется через m_IData.

//------------------------------------------------------------
class A::InternalData {
public:
int m_Value;
char *m_Str;
static int g_Instances;
void init() {
g_Instances++;
}
};
int A::InternalData::g_Instances=0;
A::A(char *Str, int Val) {
m_IData=new InternalData();
m_IData->m_Value=Val;
m_IData->m_Str=Str;
m_IData->init();
}
void A::~A() {
delete m_IData;
}
//------------------------------------------------------------

@темы: .DLL, Трюки с наследованием

URL
   

Записная книжка программиста C++

главная