Неполный тип: использование класса до определения или прямого объявления

Я знаю, что мы не можем определить функции, принимающие неполный тип в качестве параметра, поэтому ожидается, что приведенный ниже код не скомпилируется с ошибка C2027: использование неопределенного типа ‘Derived’

class Derived;
class Base{
public:
void test(Derived d){ cout<<"test"<<endl; }
};
class Derived : public Base{
int j;
};

По той же логике я бы ожидал, что компиляция завершится неудачно, когда test () получит объект Base, который до этого момента имеет неполный тип. Тем не менее, это не так, и следующий код прекрасно компилируется

class Derived;
class Base{
public:
void test(Base b){ cout<<"test"<<endl; }
};
class Derived : public Base{
int j;
};

Есть ли разница между неполным типом класса, который есть у нас во время определения класса, и незавершенным типом, предоставляемым предварительным объявлением?

1

Решение

Логика не та же самая. Разница в том, что в вашем втором примере функции Base::test() использует объекты своего класса Base (в отличие от полностью иностранного класса Derived).

Язык дает особый подход к этой ситуации в 8.3.5 / 6 (C ++ 03)

Тип параметра или тип возвращаемого значения для определения функции
не должен быть неполным типом класса (возможно, cv-квалифицированным), если только
определение функции вложено в спецификацию члена для
этот класс (включая определения во вложенных классах, определенных в
учебный класс).

Это правило можно рассматривать как «спутник» для другого подобного правила — того, которое говорит, что тип класса всегда рассматривается полностью (и как полный тип) из тел функций-членов класса, аргументов по умолчанию и списков инициализатора конструктора. См. 9.2 / 2 (C ++ 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`
{}
};
3

Другие решения

Других решений пока нет …