Я знаю, что мы не можем определить функции, принимающие неполный тип в качестве параметра, поэтому ожидается, что приведенный ниже код не скомпилируется с ошибка 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;
};
Есть ли разница между неполным типом класса, который есть у нас во время определения класса, и незавершенным типом, предоставляемым предварительным объявлением?
Логика не та же самая. Разница в том, что в вашем втором примере функции 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`
{}
};
Других решений пока нет …