[c++] использование классов во время их объявления
иначе получается, что оба класса требуют, чтобы каждый из них был полностью задефайнен. замкнутый круг.
Если да, то как можно выкрутиться, если нужно описать структуру данных, ссылающуюся на себя.struct S
{
S* pS;
};
Или тебе нужно что-то особенное?
![](/images/graemlins/shocked.gif)
У тебя значения констант меняться должны в разных классах или что? Если да, то вот такой код компилиться, хотя на мой взгля .... ладно промолчу.
У меня вот так скомпилилось:
template <typename T> class A
{
public:
enum { N = 1 } asd;
T x;
};
struct B;
class A<B>
{
enum { N = 7 };
};
struct B
{
int x;
enum { M = A<B>::N };
};
![](/smiles/alien5.gif)
class B {
public:
int x;
enum { M = A<char>::N };
};
или никак
Вообще говоря, подобные циклические конструкции весьма сложны для анализа и отладки, и, имхо, лучше их избегать. То есть желательно, чтобы либо A ничего не знал о B (как у либо B ничего не знал об A.
Зависимость здесь по существу, попытаюсь объяснить подробнее.
Есть некий класс A, который содержит данные и указатель на какие-то другие елементы класса A, по типу списка, дерева. Например так:
class A
{
int data;
A* left;
A* right
};
тут все понятно - работает без проблем.
Далее - A* меняется на продвинутые (smart) указатели, например что-нибудь в духе
class A
{
int data;
shared_ptr<A> left;
shared_ptr<A> right;
}
Такое тоже более-менее работает. Допустим shared_ptr реализуется так:
template <typename T> class RCBase
{
public:
int refcount;
T data;
};
template <typename T> class shared_ptr
{
private:
RCBase<T> *ptr;
public:
...
shared_ptr& operator = (constr shared_ptr& b) {
RCBase<T> old = ptr;
ptr = b.ptr;
if (ptr) ptr->refcount++;
if (old) old->refcount--;
}
// не буду вдаваться в детали, здесь это неважно
}
Что мы видим: shared_ptr<T> использует RCBase<T>, RCBase<T> использует T, A использует shared_ptr<A> --- то есть получается цикл.
Я привел пример с enum, потому что он у меня не компилися. Ладно, допустим c enum-ами я как-нибудь разобрался, фиг с ним. В приведенном примере все равно получается цикл. Причем цикл по существу, я не вижу нормальных способов его устранить. Соответственно, вопрос: как надо писать классы A, shared_ptr, RCBase, чтобы вся эта конструкция скомпилилась? На примере enum я понял, что как попало писать нельзя, надо аккуратно. Какие еще есть ограничения?
shared_ptr& operator = (constr shared_ptr& b) {
RCBase<T> old = ptr;
old тоже должен быть
RCBase<T>* old
и вроде пока всё нормально)
как-то странно выглядит
class A<B> {
};
Вообще, должно работать на других тоже - я не раз встречал такое объявление.
А какое имя у описанного класса?
> RCBase<T>* old
Да, здесь я опечатался, имелось ввиду *
> и вроде пока всё нормально)
В таком виде как я написал --- компилится. Но тут есть два вопроса:
1) Это компилится конкретно моим компилятором. Насколько это переносимо? Будет ли это компилится другими компиляторами? Насколько это соотвествует стандарту?
2) То, что я описал --- это в некотором роде скелет, каркас. Простой пример, показывающий, как циклические зависимости между классами иногда действительно нужны. В реальности, в программе должна быть еще куча разных содержательных методов. И в них как раз не понятно, что можно использовать, а что нельзя, чтобы случайно не нарваться на какой-нибудь 'Incomplete type ...'
c:\documents and settings\dmitry\my documents\visual studio 2005\projects\cmasmastest\cmasmastest.cpp(22) : error C2440: 'initializing' : cannot convert from 'RCBase<T> *' to 'RCBase<T>'
class A obj1, obj2;
obj1 = obj2;
Думаю, что всёже не так-то и просто пример такой хитрой зависимости привести, чтоб реально нужно было, хотя вопрос, конечно, и интересный)
А какое имя у описанного класса?A<B>
2) Важно, чтобы все конструкции, которые расположены в объявлении класса shared_ptr вне его методов, не использовали класс A непосредственно, а только через указатель, то есть не привязывались к его структуре. Внутри методов (в том числе inline) этот указатель уже можно разыменовывать, так как при этом циклической зависимости не возникает.
P.S. Небольшой оффтопик: не стоит ли RCBase описать внутри класса shared_ptr?
Оставить комментарий
Landstreicher
Насколько разрешен сабж?Например, у меня не компилится следующая программа:
Компилятор gcc 4.0, 4.1.
Соответствует ли такое поведение стандарту? Если да, то как можно выкрутиться, если нужно описать структуру данных, ссылающуюся на себя.