2014-02-20 3 views
7

Я хотел бы, чтобы переместить вложенный класс Inner из Outer.h в отдельном файле заголовка:C++ вложенный класс в файле разделенных заголовка

class Outer{ 
    class Inner{ 
    public: 
     Inner(Outer& o){} 
    }; 

public: 
    Outer():i(*this){} 
    ~Outer(){} 
    Inner i; 
}; 

И 'main.cpp'

#include "Outer.h" 
int main(){ 
    Outer o; 
    return 0; 
} 

Но как только я пытаюсь поместить внутренний класс внутри отделенной головой, как это:

class Outer{ 
    class Inner; 

public: 
    Outer():i(*this){} 
    ~Outer(){}; 
    Inner i; 
}; 

и поместить внутренний класс в «Inner.h», как это:

class Outer::Inner{ 
public: 
    Inner(Outer& o){} 
}; 

и добавить в основную #include 'Inner.h', как это:

#include "Outer.h" 
#include "Inner.h" 
int main(){ 
    Outer o; 
    return 0; 
} 

Я получаю следующее сообщение об ошибке от компилятора: Outer.h: 10: 9: ошибка: поле ' i 'имеет неполный тип.

Я понимаю более или менее, почему, но я не могу найти проблему для достижения того, что я хочу делать.

ответ

5

Чтобы создать объект Outer, расположение памяти класса должно быть известно, и в этом случае оно не является (именно из-за неполноты Inner).

Способ использования этого указателя заключается в том, чтобы использовать указатель вперед (как указатель имеет фиксированный размер, и тогда будет известна макет памяти Outer).


Что я имею в виду:

// header file 
class Outer{ 
    class Inner; 

public: 
    Outer(); 
    ~Outer(); 

    Inner* i; 
}; 

И затем, в исходном файле класса Outer, определить

// include header file for Outer and Inner classes 

// source file 
Outer::Outer() 
{ 
    i = new Inner(*this); 
}; 
Outer::~Outer() 
{ 
    delete i; 
}; 

Вы должны сделать это в исходном файле, потому что вы необходимо указать include файл заголовка класса Inner (вы не можете include его в файл заголовка напрямую, потому что вы столкнетесь с круговой (два файла заголовка будут включать друг друга), поскольку заголовочный файл Inner также будет иметь заголовочный файл Outer).


Это также известен как Pimpl идиомы - «указатель на реализацию» и часто Inner называется Impl и член pImpl или что-то подобное, в зависимости от используемой конвенции кодирования. Идея состоит в том, чтобы скрыть любые детали реализации, такие как частные/защищенные члены (функции, данные).

+0

Не следует ли определять определение «Внутренний», чтобы определить конструктор «Наружный», как вы это делали? –

+0

@NicolaMusatti - спасибо, исправлено. –

+0

Большое спасибо за вашу помощь! – bou

1

Если вы не хотите, чтобы превратить ваш i элемент в указатель ваш лучший вариант, чтобы переместить определение из Inner снаружи Outer и использовать пространство имен для гнездования.

Обратите внимание, что в этом случае вам необходимо будет включить заголовок Inner.h до определения Outer.

+0

Благодарим вас за этот совет. – bou

Смежные вопросы