С давних пор с настороженностью отношусь к опережающим объявления (forward declarations) типов в коде. Когда вижу что-то вроде:
class A;
class B;
class C {
const A * _a;
B & _b;
...
};
то невольно начинаю ждать неприятных приключений. Коих, по моим наблюдениям, бывает два вида.
Во-первых, некоторые компиляторы (не будем показывать пальцем в сторону VC++) различают:
class A;
и
struct A;
Поэтому если в каком-то заголовочном файле есть что-то вроде:
class A;
void f(const A &);
А затем в файле реализации:
struct A { ... };
void f(const A & a) { ... };
то при линковке нужная версия f может и не обнаружиться.
Во-вторых, может оказаться, что где-то осталось:
class A;
Тогда как основное определение A было преобразовано в:
template<typename T>
class SomeTrickyTemplate { ... };
using A = SomeTrickyTemplate<int>;
И мы опять же получим приключения при линковке.
Конечно же хорошо, что все сломается при линковке и нам не придется разбираться с непонятным поведением exe файла, т.к. самого exe файла не будет. Но если у разработчика небольшой опыт в C++, то разобраться с ошибками от линкера ему будет непросто.
Поэтому лично я стараюсь держать опережающие объявления под контролем в специально огороженных загончиках. Либо кучу разных объявлений в одном файле (например), либо же только то, что относится к какому-то одному типу (например). Смысл есть и в том, и в другом вариантах.
Но вот когда опережающие объявления без контроля разбросаны по всему проекту, вот это меня сильно напрягает.
Комментариев нет:
Отправить комментарий