Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.85/20: Рейтинг темы: голосов - 20, средняя оценка - 4.85
Revion
1 / 1 / 0
Регистрация: 09.05.2010
Сообщений: 4
#1

Перекрёстные ссылки в объявлениях классов

09.05.2010, 16:50. Просмотров 3638. Ответов 8
Метки нет (Все метки)

Предположим есть класс uiObject и класс ObjectController.
Класс uiObject имеет метод GetController, который выплюнет контроллер. А класс ObjectController имеет метод GetObject, который вернёт подконтрольный объект. Эти два класса являются базовыми и далее от них наследуются классы uiState и StateController. Отличия в наследниках состоит в том, что GetObject возвращает uiState, а GetController возвращает StateController.

Реализация базовых классов какая-нибудь такая:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//**ObjectController.h
class uiObject;
 
class ObjectController
{
public:
    ObjectController() {}
    virtual ~ObjectController() {}
 
    virtual uiObject* GetOne();
};
 
//**uiObject.h
class ObjectController;
 
class uiObject
{
public:
    uiObject() {}
    virtual ~uiObject() {}
 
    virtual ObjectController* GetController();
};
И производных какая-то такая:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//**uiState.h
 
#include "uiObject.h"
#include "StateController.h" // <- это 1ый перекрёстный инклуд
 
class uiState
    : public uiObject
{
public:
    uiState() {}
    virtual ~uiState() {}
 
    virtual StateController* GetTwo();//<- компилятору нужно как-то сказать,
                                                            //    что StateController потомок ObjectController, 
                                                            //    для чего включён StateController.h
 
};
 
//**StateController.h
 
#include "ObjectController.h"
#include "uiState.h" // <- это 2ой перекрёстный инклуд
 
class StateController
    : public ObjectController
{
public:
    StateController() {}
    virtual ~StateController() {}
 
    virtual uiState* GetOne(); //<- здесь тоже самое. Включён uiState.h
};
Беда состоит в том, что это не хочет компилится из-за перекрёстных ссылок в ш-никах : ).

В итоге после обработки препроцессором StateController.cpp, который просто включает StateController.h получается нечто вроде:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//**         StateController.cpp
#line 1 "d:\\учеба\\_sourcecode\\qqwe\\qqwe\\statecontroller.h"
#pragma once
 
#line 1 "d:\\учеба\\_sourcecode\\qqwe\\qqwe\\objectcontroller.h"
#pragma once
 
class uiObject;
 
class ObjectController
{
public:
    ObjectController() {}
    virtual ~ObjectController() {}
 
    virtual uiObject* GetOne();
};
#line 4 "d:\\учеба\\_sourcecode\\qqwe\\qqwe\\statecontroller.h"
#line 1 "d:\\учеба\\_sourcecode\\qqwe\\qqwe\\uistate.h"
#pragma once
 
#line 1 "d:\\учеба\\_sourcecode\\qqwe\\qqwe\\uiobject.h"
#pragma once
 
class ObjectController;
 
class uiObject
{
public:
    uiObject() {}
    virtual ~uiObject() {}
 
    virtual ObjectController* GetController();
};
#line 4 "d:\\учеба\\_sourcecode\\qqwe\\qqwe\\uistate.h"
 
 
class uiState
    : public uiObject
{
public:
    uiState() {}
    virtual ~uiState() {}
 
    virtual StateController* GetTwo();
};
#line 5 "d:\\учеба\\_sourcecode\\qqwe\\qqwe\\statecontroller.h"
 
class StateController
    : public ObjectController
{
public:
    StateController() {}
    virtual ~StateController() {}
 
    virtual uiState* GetOne();
};
Из чего видно почему оно не компилится.

Вопрос: КАК реализовать такую перекрёстную классовую архитектуру на спп? Я бы стал очено грустным, если из-за вот таких заморочек компилятора этого сделать было бы невозможно : /
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.05.2010, 16:50
Ответы с готовыми решениями:

Создание java классов в коде С++ и вызов Java методов и классов из C++
Здравствуйте! Собственно проблема вот в чем при клмпиляции получаю ошибки ...

Объяснить разницу в объявлениях указателя
Добрый вечер. Объясните, пожалуйста, в чем разница записи, если я ставлю...

Об объявлениях функций и хорошем тоне
Здравствуйте. Как предпочтительней: void f() { /* do smt */ } int...

Есть ли разница в данных объявлениях массива?
string *array={&quot;string1&quot;,&quot;string2&quot;}; string array = {&quot;string1&quot;,&quot;string2&quot;}; ...

Разработать иерархию классов, демонстрирующее работу с коллекцией объектов разных классов
Задание: Разработать в соответствии с индивидуальным заданием иерархию классов...

8
Aye Aye
370 / 284 / 97
Регистрация: 17.12.2009
Сообщений: 567
09.05.2010, 18:32 #2
так тебе нужно что бы не было прекрестных включений заголовочников, наверно а не "перекрёстной классовой архитектуры"
в каждый херед добавь:
C++
1
2
3
4
5
6
7
8
9
10
11
#ifndef UIOBJECT
#define UIOBJECT
 // тут класс uiObject
#endif
 
//а во второй
 
#ifndef OBJECTCONTROLLER
#define BJECTCONTROLLER
 // тут класс ObjectController
#endif
должно помоч
1
Genius Ignat
09.05.2010, 18:54
  #3

Не по теме:

херед
Создатели языков C and C++ не могли предположить что будут такие оговорки.
Улыбнуло. +1

0
Revion
1 / 1 / 0
Регистрация: 09.05.2010
Сообщений: 4
09.05.2010, 22:02  [ТС] #4
Эттттооо, на самом деле я просто опустил #pragma once когда описывал хедеры. Оно там есть. И это не помогает и дело не в этом.
А дело в том что в одном цпп уже после обработки препроцессором получатся так что один класс использует другой, который объявлен ниже.
С этим как бэ борются используя форвард декларейшн типа:

class uiState; или class StateController;

Но тут это не прокатывает! Потому как нужно не просто сказать компилятору что такой класс есть, но и указать что этот самый класс является наследником другого класса (uiObject/ObjectController)
Сколько я ни пробовал записи типа:

class uiState : public uiObject;

Компайлер, #@%№, считает это уже объявлением класса а не его декларацией : (, что не может не огорчать.

Хеееееелп!!!!! Как это разрешить не знаю(((
0
Aye Aye
370 / 284 / 97
Регистрация: 17.12.2009
Сообщений: 567
10.05.2010, 05:52 #5
вот что я сделал:
main.cpp:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "etier.h"
#include "A.h"
#include "B.h"
#include "A1.h"
#include "B1.h"
int main()
{
    A a;
    A1 a1;
    B b;
    B1 b1;
    return 0;
}
A.h:
C++
1
2
3
4
#include "etier.h"
class A{
    B *bptr(){}
};
A1.h:
C++
1
2
3
4
5
#include "etier.h"
class A1: public A
{
    virtual B1* bptr(){}
};
B.h:
C++
1
2
3
4
#include "etier.h"
class B{
    A *aptr(){}
};
B1.h:
C++
1
2
3
4
5
#include "etier.h"
class B1: public B
{
    virtual A1* aptr(){}
};
etier.h:
C++
1
2
3
4
5
6
7
#ifndef ENTIER
#define ENTIER
class A;
class A1;
class B;
class B1;
#endif
компиляция:
Код
C:\Program Files\CodeBlocks\MinGW\bin>g++ test/main.cpp -E > log.txt
log.txt:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 1 "test/main.cpp"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test/main.cpp"
# 1 "test/etier.h" 1
 
 
class A;
class A1;
class B;
class B1;
# 2 "test/main.cpp" 2
# 1 "test/A.h" 1
 
class A{
    B *bptr(){}
};
# 3 "test/main.cpp" 2
# 1 "test/B.h" 1
 
class B{
    A *aptr(){}
};
# 4 "test/main.cpp" 2
# 1 "test/A1.h" 1
 
class A1: public A
{
    virtual B1* bptr(){}
};
# 5 "test/main.cpp" 2
# 1 "test/B1.h" 1
 
class B1: public B
{
    virtual A1* aptr(){}
};
# 6 "test/main.cpp" 2
int main()
{
    A a;
    A1 a1;
    B b;
    B1 b1;
    return 0;
}
скомпилировалось без ошибок и предупреждений. я использовал среду code blocks. Если ты такой среды не знаешь и хочешь скомпилировать проект в ней, то вот что надо сделать: установить среду (само собой), открыть файл test.cbp, и нажать на синенький треугольник вверху.
если не получится собрать то вот makefile:
Bash
1
2
3
4
5
6
7
# makefile для проекта test
 
test: main.o
    g++ main.o -o test
 
main.o: A.h A1.h B.h B1.h etier.h
    g++ -c main.cpp
хотя я его не проверял.
П.С. etier.h - это я опечатался в самом начале, потом лень было исправлять, правильно entier.h - "полный".
архив с проектом прилагается.
0
Вложения
Тип файла: zip test.zip (15.3 Кб, 11 просмотров)
Aye Aye
370 / 284 / 97
Регистрация: 17.12.2009
Сообщений: 567
10.05.2010, 05:58 #6
а, пардон!, предупреждения при сборке были, только я без -Wall компилировал по этому они не вывелись в первый раз... наверно.
надеюсь это то, что нужно. Компилятор C++ может все, даже крестиком вышивать
0
Revion
1 / 1 / 0
Регистрация: 09.05.2010
Сообщений: 4
12.05.2010, 13:29  [ТС] #7
Aye Aye, спасибо : ) Раньше не пользовался другими компиляторами кроме как VC.

Но, проблему это не решает.
Aye Aye, то что ты привёл, действительно компилируется. Но это не то, что я описывал вверху. Ты не указал виртуал у методов bptr и aptr у базовых классов. Если его указать, то и г++ также выводит ошибку, точнее даже 2..

Решение было найдено по ссылке http://stackoverflow.com/questions/1...are-covariance . Точнее 2 : ). И весьма интересных надо сказать.
Первое используя шаблоны и позднее связывание, а второре НЕ виртуальные функции + виртуальные для статической типизации. По ссылке они оба есть.

Действительно крестиком компилятор вышивать умеет, но не без заморочек.
1
Aye Aye
370 / 284 / 97
Регистрация: 17.12.2009
Сообщений: 567
12.05.2010, 23:22 #8
Revion, прошу прощения за невнимательность! Спасибо за ссылочку, полезная. Только теперь уже я не понимаю, где там определяются doFoo(); и doBar();?
0
Revion
1 / 1 / 0
Регистрация: 09.05.2010
Сообщений: 4
14.05.2010, 02:19  [ТС] #9
doFoo и doBar не определены, но это и не важно. Они будут определены как понадобится
Главное что они виртуальные и когда вызовется foo или bar вызовуться именно те doFoo и doBar, которые соответствуют _динамическому_ типу объекта.
А за счёт переопределения типа функции foo и bar, обходится covariance ошибка.

Хотя мне лично значительно больше нравится вариант с шаблонами. : ) Если ещё потом воткнуть тупедеф, то не нужно будет каждый раз рисовать скобки <> для создания объекта.
Так что решение с шаблонами почти идеальное на мой взгляд, что не изменно радует : )
0
14.05.2010, 02:19
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.05.2010, 02:19

Вынести методы из классов Panel и PictureBox (явная реализация методов базовых абстрактных классов)
Тема: Множественное наследование. Явная реализация методов базовых абстрактных...

Объекты классов не видны во вложенной функции одной из классов
Такая вот проблема. Есть функция play() класса Game, где создаются объекты...

Реализация отношения классов типа двунаправленная ассоциация, UML, порядок объявления классов, неполный класс
Доброго времени суток! Осваивая UML, решил реализовать отношение...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru