Question

I know we can not define functions taking incomplete type as parameter, so it is expected the below code fails to compile with error C2027: use of undefined type 'Derived'

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

By the same logic, I would expect compilation to fail when test() takes an object of Base, which is of incomplete-type till that point. However, it does not, and the following code compiles fine

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

Is there a difference between the incomplete class type we have while a class is being defined and the incomplete-type exposed by a forward declaration?

Was it helpful?

Solution

The logic is not the same. The difference is that in your second example function Base::test() uses objects of its own class Base (as opposed to a completely foreign class Derived).

The language gives a special treatment to this situation in 8.3.5/6 (C++03)

The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).

This rule can be seen as a "satellite" for another similar rule - the one that says that the class type is always seen in its entirety (and as complete type) from bodies of class member functions, default arguments and constructor initializer lists. See 9.2/2 (C++03)

A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments and constructor ctor-initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

Note that in all other contexts before the closing } the class is considered to be incomplete

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`
    {}
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top