Reputation: 69
I have 2 classes that depend on each other and I can't find a way to get forward declaration to work. I know how to do it using multiple cpp and header files, I was just curious if there's a way to do it in a single file.
class cls2;
class cls1
{
public:
int vi;
cls1(int v = 30)
{
vi = v;
}
cls1(cls2 p)
{
vi = p.vi;
}
};
class cls2
{
public:
int vi;
cls2(int v = 20)
{
vi = v;
}
cls2(cls1 p)
{
vi = p.vi;
}
};
The error I get is:
error: 'p' has incomplete type
Upvotes: 1
Views: 72
Reputation: 310980
This error message
error: 'p' has incomplete type
means that in the point of the constructor definition
cls1(cls2 p)
{
vi = p.vi;
}
the compiler does not know yet how the class cls2
is defined and whether it has the data member vi
.
You can define constructors only when the class used as a parameter is a complete type.
For example
class cls2;
class cls1
{
public:
int vi;
cls1(int v = 30)
{
vi = v;
}
cls1(cls2 p);
};
class cls2
{
public:
int vi;
cls2(int v = 20)
{
vi = v;
}
cls2(cls1 p)
{
vi = p.vi;
}
};
cls1::cls1(cls2 p)
{
vi = p.vi;
}
Or instead of this forward declaration
class cls2;
you may use an elaborated type specifier in the constructor declaration of the class cls1
For example
class cls1
{
public:
int vi;
cls1(int v = 30)
{
vi = v;
}
cls1( class cls2 p);
};
class cls2
{
public:
int vi;
cls2(int v = 20)
{
vi = v;
}
cls2(cls1 p)
{
vi = p.vi;
}
};
cls1::cls1(cls2 p)
{
vi = p.vi;
}
It is interesting to note that using the constructors of the classes you can get an unexpected result.
For example for this declaration
cls1 c{ { 10 } };
there will be called this constrictor
cls1(int v = 30)
{
vi = v;
}
But if you add one more pair of braces like this
cls1 c{ { { 10 } } };
then there will be called this constructor
cls1::cls1(cls2 p)
{
vi = p.vi;
}
Here is a demonstrative program.
#include <iostream>
class cls1
{
public:
int vi;
cls1(int v = 30)
{
std::cout << "cls1( int )\n";
vi = v;
}
cls1( class cls2 p);
};
class cls2
{
public:
int vi;
cls2(int v = 20)
{
vi = v;
}
cls2(cls1 p)
{
vi = p.vi;
}
};
cls1::cls1(cls2 p)
{
std::cout << "cls1( cls2 )\n";
vi = p.vi;
}
int main()
{
cls1 c1 { { 10 } };
cls1 c2 { { { 10 } } };
// or
// cls1 c1 { { } };
// cls1 c2 { { { } } };
}
The program output is
cls1( int )
cls1( cls2 )
Upvotes: 1
Reputation: 38499
Use references, that do not produce copies, thus no complete class declarations are required. And split method definitions, move them to the point where class declarations are complete.
class cls2;
class cls1
{
public:
int vi;
cls1(int v = 30)
{
vi = v;
}
cls1(const cls2& p);
};
class cls2
{
public:
int vi;
cls2(int v = 20)
{
vi = v;
}
cls2(const cls1& p)
{
vi = p.vi;
}
};
cls1::cls1(const cls2& p)
{
vi = p.vi;
}
Upvotes: 3
Reputation: 118681
The error is happening because the constructor needs to know how to copy the cls2
object. You can solve this by moving the cls1
constructor implementation after the cls2
declaration:
class cls2;
class cls1
{
public:
int vi;
cls1(int v = 30)
{
vi = v;
}
cls1(cls2 p);
};
class cls2
{
public:
int vi;
cls2(int v = 20)
{
vi = v;
}
cls2(cls1 p)
{
vi = p.vi;
}
};
cls1::cls1(cls2 p) {
vi = p.vi;
}
Upvotes: 0