Взаимно ссылающиеся классы: 1)Проблема описания 2)ошибка IntelliSense
От: Sasha_K  
Дата: 28.03.14 19:41
Оценка:
Столкнулся с такой ситуацией:


class A; //объявление А (т.н. "forward declaration")

class E { //описание Е
public:
   void static changeA(A&);
};

class A { //описание А
public:
   A() : d(1) {};
   void show(void) {
      printf("d=%i",d);
   }
   friend void E::changeA(A&);
private:
   int d;
};

void E::changeA(A& x){
   x.d = 123;
}

void main(void) {
   A a;
   E::changeA(a);
   a.show();
}

получаю вывод: "d=123"

Тут приведен рабочий код. Изначально с ним имел проблемы, когда этот код имел структуру:

forward declaration Е;
описания класса А
(вместе с его методами);
описание класса Е (вместе с его методами);

В этом случае компилятор ругался: "error C2027: использование неопределенного типа "E" ".
Это мой первый вопрос: Подскажите пожалуйста, мне вот не ясно, ведь тип "Е" он на самом деле уже видит, скорее всего (предполагаю) он реально не видит при такой последовательности описаний классов метод changeA() (член класса Е). Так ли это? (т.е. компилятор просто нечётко выражается, или это я не понимаю, чего-то).

Но эту проблему смог решить в виде приведённого кода — программа заработала.
Вопрос №2: можно ли как-то иначе было решить эту проблему (не перенося описание класса Е перед описанием А. В данном случае класс Е мне пришлось ещё и разорвать: описание перед А, а определение метода changeA() — после (метод пришлось оставить после А, т.к. он обращается к полю класса А).
Я пытался подобрать нечто вроде прототипа метода changeA() и его указать перед кл. А, тогда все описание Е не пришлось бы переносить, но не удалось (видимо просто невозможно объявить метод вне класса).

Последний 3-ий вопрос: в этом варианте кода всё работает верно, но, тем не менее, IntelliSense выдаёт ошибку, которая не мешает запустить программу:
"IntelliSense: член "A::d" (объявлено в строке 17) недоступно"
и подчёркивает его красным в тексте кода.
Собственно вопрос #3: Почему так? IntelliSense ошибается? (ведь доступно же!) Если да, то как на будущее определить, на какие его сообщения об ошибках не стоит обращать внимание?

Благодарю за Вашу помощь!
//
Re: Взаимно ссылающиеся классы: 1)Проблема описания 2)ошибка IntelliSense
От: Хреннос  
Дата: 28.03.14 20:39
Оценка: 3 (1)
Здравствуйте, Sasha_K, Вы писали:

S_K>Тут приведен рабочий код. Изначально с ним имел проблемы, когда этот код имел структуру:


S_K> forward declaration Е;

S_K> описания класса А
(вместе с его методами);
S_K> описание класса Е (вместе с его методами);

S_K>В этом случае компилятор ругался: "error C2027: использование неопределенного типа "E" ".

S_K>Это мой первый вопрос: Подскажите пожалуйста, мне вот не ясно, ведь тип "Е" он на самом деле уже видит, скорее всего (предполагаю) он реально не видит при такой последовательности описаний классов метод changeA() (член класса Е). Так ли это? (т.е. компилятор просто нечётко выражается, или это я не понимаю, чего-то).

Предварительное объявление класса Е не дает компилятору знания о методах класса. Это так называемый неполный тип. На него можно объявить ссылку или указатель, но вызывать методы или создавать объекты этого типа нельзя.

S_K>Но эту проблему смог решить в виде приведённого кода — программа заработала.

S_K>Вопрос №2: можно ли как-то иначе было решить эту проблему (не перенося описание класса Е перед описанием А. В данном случае класс Е мне пришлось ещё и разорвать: описание перед А, а определение метода changeA() — после (метод пришлось оставить после А, т.к. он обращается к полю класса А).

Иначе решать незачем.
В реальных проектах объявление класса содержится в заголовочном файле, а реализация — в файле реализации. Поэтому их порядок друг относительно друга просто отсутствует — они в разных единицах трансляции.

S_K>Я пытался подобрать нечто вроде прототипа метода changeA() и его указать перед кл. А, тогда все описание Е не пришлось бы переносить, но не удалось (видимо просто невозможно объявить метод вне класса).


Невозможно, ага.

S_K>Последний 3-ий вопрос: в этом варианте кода всё работает верно, но, тем не менее, IntelliSense выдаёт ошибку, которая не мешает запустить программу:

S_K>"IntelliSense: член "A::d" (объявлено в строке 17) недоступно"
S_K>и подчёркивает его красным в тексте кода.
S_K>Собственно вопрос #3: Почему так? IntelliSense ошибается? (ведь доступно же!) Если да, то как на будущее определить, на какие его сообщения об ошибках не стоит обращать внимание?

Интеллисенс, скорее всего, сбило с панлатыку то, что ты объявляешь френдом не весь класс Е, а только его конкретный член. Во всех примерах, которые мне помнятся, френдом объявляется или отдельностоящая функция (не член класса), или весь класс.

S_K>Благодарю за Вашу помощь!


Не за что.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.