Ответ 1
Логика не то же самое. Разница в том, что в вашем втором примере функция Base::test()
использует объекты своего класса Base
(в отличие от полностью иностранного класса Derived
).
Язык дает особое отношение к этой ситуации в 8.3.5/6 (С++ 03)
Тип параметра или тип возвращаемого значения для определения функции не должен быть неполным классом (возможно, cv-квалифицированным), если только определение функции вложено в спецификацию члена для этот класс (включая определения в вложенных классах, определенных в класс).
Это правило можно рассматривать как "спутник" для другого аналогичного правила - тот, который говорит, что тип класса всегда отображается целиком (и как полный тип) из тел функций-членов класса, аргументов по умолчанию и инициализатора конструктора списки. См. 9.2/2 (С++ 03)
Класс считается полностью определенным типом объекта (3.9) (или полным типом) при закрытии} класса спецификатор. В рамках класса-класса класс считается полным в функции тела, аргументы по умолчанию и конструктор ctor-инициализаторы (включая такие вещи во вложенных классах). В противном случае он считается неполным в пределах своей спецификации члена класса.
Обратите внимание, что во всех других контекстах до закрытия }
класс считается неполным
struct S {
S foo(S s) // <- OK, due to 8.3.5/6
{ return s; }
void bar(int a = sizeof(S)) // <- OK, due to 9.2/2
{ S s; } // <- OK, due to 9.2/2
int (*baz())[sizeof(S)] // <- ERROR: incomplete type in `sizeof`
{ return NULL; }
void qux(int a[sizeof(S)]) // <- ERROR: incomplete type in `sizeof`
{}
};