Я пишу бэкэнд компилятора подмножества Java. Бэкэнд пишет код C ++. Тем не менее, есть некоторый гипотетический код Java, который я не знаю, как перевести на C ++.
Пример проблемы показан в следующем коде. A расширяется на B, B расширяется на C, и вот соответствующие три заголовочных файла A.h, B.h и C.h:
#ifndef A_H
#define A_H
class B;
class A {
public: virtual B* get();
}
#endif /* !defined(A_H) */
==========================
#ifndef B_H
#define B_H
#include "A.h"
class C;
class B : public A {
public: virtual C* get();
}
#endif /* !defined(B_H) */
==========================
#ifndef C_H
#define C_H
#include "B.h"
class C : public B {
}
#endif /* !defined(C_H) */
Как видно, B переопределяет метод get (). Переопределяющий метод возвращает указатель на соответствующий подкласс, который, я думаю, действителен в C ++, благодаря ковариантности.
То, что я не знаю, это способ информирования компилятора о том, что C действительно является подклассом B, и, следовательно, что переопределяющий метод действителен.
Предварительного объявления C в B.h, как и в коде, недостаточно, поскольку оно ничего не говорит о суперклассах C.
Включение C.h в B.h будет круглым, поскольку C.h уже включает B.h. Последнее необходимо, потому что недостаточно иметь только предварительное объявление суперкласса.
Что можно с этим сделать?
РЕДАКТИРОВАТЬ Два замечания.
1 Один из авторов утверждает, что в Java невозможно следующее, поэтому я добавляю версию Java:
A.java:
class A {
public B get() {
return null;
}
}
B.java:
class B extends A {
public C get() {
return null;
}
}
C.java:
class C extends B {
}
Отлично компилируется.
2 Я не настаиваю на составлении таких странных случаев. Если они не могут быть переведены в читаемый код на C ++, то нормально, бэкэнд просто потерпит неудачу с сообщением об ошибке. На самом деле меня больше интересует общий способ разрешения циклических зависимостей, подобный тому, который есть в C ++.
РЕДАКТИРОВАТЬ 2
Спасибо всем, я впечатлен эффективностью этого сайта.
Я пришел к выводу, потому что:
- созданные файлы заголовков будут использоваться другими программистами;
- догадываясь из ваших ответов, скорее всего, не существует решения, которое дало бы простые читаемые заголовочные файлы;
- циклические ссылки с возвращаемыми типами, вероятно, редки;
- Я избегаю C ++, потому что, среди прочего, он допускает подобные решения -
Я знаю, что C ++ имеет свое применение, но лично я предпочитаю языки с более простой грамматикой, такие как Java;
бэкэнд будет:
- по возможности использовать предварительные объявления;
- в противном случае он будет использовать include, проверяя, является ли последний круговым; если да, произойдет сбой с сообщением об ошибке.
Ура,
Артур