Подтвердить что ты не робот

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

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

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

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

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

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

4b9b3361

Ответ 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`
    {}
};