2010-10-20 2 views
3

У меня есть ситуация, в которой А имеет ссылку на класс C, определенных внутри В, и С имеет экземпляр класс В.взаимно ссылочные классы дают ошибку «неполный типа»

При попытке компиляции коды ниже, я получаю «field a has incomplete type». Я предполагаю, что это потому, что компилятор не знает, сколько памяти следует выделить для экземпляра А.

class A; 

class B { 
public: 
    class C { 
    A a; 
    }; 
}; 

class A { 
    A(const B::C& _c) 
    : c(_c) 
    {} 
    const B::C& c; 
}; 

Но когда я пытаюсь скомпилировать это я получаю «C in class B does not name a type»:

class B; 
class B::C; 

class A { 
    A(const B::C& _c) 
    : c(_c) 
    {} 
    const B::C& c; 
}; 


class B {  
public: 
    class C { 
    A a; 
    }; 
}; 

Как я могу убедить компилятор, что B::C является реальным типом?

ответ

5

Как абсолютная догадка, я замечаю, что есть одна перестановки вы еще не пробовали:

class B { 
public: 
    class C; // Forward declaration 
}; 

class A { 
    A(const B::C& _c) 
    : c(_c) 
    {} 
    const B::C& c; 
}; 

class B::C { 
    A a; 
    C() : a(*this) {} // Thanks Nim for pointing this out! 
}; 

Это вполне возможно, незаконные, но стоит выстрела, я думаю. Если это не сработает, я не вижу проблемы вокруг проблемы.

+1

Кажется законным. – UncleBens

+1

Я не считаю, что это скомпилируется, конструктор по умолчанию для A не инициализирует ссылку на C. Однако для того, чтобы заставить выше работать, все, что вам нужно, это конструктор для C, чтобы инициализировать A с самим собой, - но у вас есть два разных экземпляра A, возможно, это именно то, что вам нужно? (@j_random_hacker, извини, если вы это подразумевали в своем ответе!) – Nim

+0

@Nim: Хорошая точка. Кто-нибудь пытался скомпилировать это? Я (лениво) не ... –

2

Вперед декларация для A не служит цели: вы не можете объявить экземпляр неполного типа.

Что касается B::C, я не думаю, что вы можете использовать вложенные имена в неполном типе. Просто не гнездайте C в B: насколько я знаю, это не дает вам никаких существенных преимуществ * и останавливает вас от объявления вперед.

* Единственное преимущество, о котором я могу думать, это то, что вы можете определить его в частном разделе, но тогда A не имел бы с ним никаких деловых контактов.

+0

Я могу сделать это, если мне нужно, но в коде, который я пишу, имеет смысл иметь вложенный в B элемент B. Есть ли веская причина, что C++ не позволяет мне объявлять вложенные неполные типы? Или это просто причуда? –

+2

@Andrew: Кажется, вы можете это сделать (см. Ответ j_random_hacker). Является ли это сложной задачей ... Я полагаю, что другой причиной для гнездовых типов является получение имен классов, но пространство имен является для этого специальным инструментом. – UncleBens

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