Если ваш класс напрямую включает член данных данного типа (а не, кстати, указатель на этот тип или ссылку на этот тип), то вы должны иметь объявление класса доступным, чтобы компилятор знал, какмного байтов экземпляр вашего объекта занимает.Обычно это означает, что вам необходимо #include
файлы заголовков.
Однако существуют методы, известные как брандмауэры компилятора, которые могут позволить вам структурировать классы таким образом, чтобы дать классу доступ к объектам соответствующего типа безнепосредственно включая их.Одним из них является идиома pImpl , в которой реализация вашего класса выглядит следующим образом:
class MyClass {
public:
/* ... */
private:
struct Impl;
Impl* pImpl;
};
Здесь вы заранее объявляете структуру Impl
, содержащую реализацию вашего класса, а затем сохраняетеуказатель на структуру Impl
в классе.Поскольку наличие указателя в вашем классе не требует, чтобы размер объекта, на который он указывал, был известен, это прекрасно.Затем в файле .cpp вы можете определить структуру Impl
:
struct MyClass::Impl {
/* ... */
};
и реализовать все функции-члены класса, просто следуя указателю pImpl
на фактические поля.Это имеет недостаток, заключающийся в том, что при доступе ко всем полям требуется косвенное указание, но возможность быстрого изменения реализации класса делает это полезным.
Другой вариант в том же духе - сделать класс абстрактным базовым классом,затем предоставить статическую фактор-функцию, которая возвращает объект, подклассифицирующий ваш базовый класс, который фактически содержит реализацию.Например:
class MyClass {
public:
virtual ~MyClass(); /* Need virtual dtors in polymorphic classes! */
virtual void doSomething() = 0;
/* ... etc. ... */
static MyClass* New(/* ... args ... */);
};
Затем в файле .cpp вы можете определить конкретный подкласс MyClass
, который фактически выполняет всю работу:
class ActualClass: public MyClass {
public:
void doSomething();
/* ... etc. ... */
private:
/* ... data members ... */
}
и, наконец, реализовать New
для создания нового экземпляра класса реализации:
MyClass* MyClass::New(/* ... args ... */) {
return new ActualClass(/* ... args ... */);
}
Надеюсь, это поможет!