Reputation: 1825
Given the below classes are in two separate header files and can appear in any order:
//TestB.h
class TestB; //Forward declaration for a later operator= in a centralised header
class TestA
{
const TestA&operator=(const TestB); //defined in Test.h
};
And:
//TestA.h
class TestA; //Forward declaration for a later operator= in a centralised heaer
class TestB
{
const TestB&operator=(const TestA); //defined in Test.h
};
How do I avoid the prototype conflict?
Help is appreciated.
I absolutely apologise to everyone! I had intended for there to be references (ampersands in the operator= arguments - I would never pass by copying bar simple PODs) and meant the question solely about prototyping conflicts! I guess it goes to show the importance of proof-reading! I have accepted the answer given the original (my erroneous) context.
I had merely only turned away for a few minutes and was not aware of the fault!
Upvotes: 5
Views: 1644
Reputation: 477100
My original answer seems to be completely wrong.
Check that you have include guards in all your header files so you don't end up with an infinite inclusion chain. Then include the headers in each implementation:
// A.cpp
#include "A.h"
#include "B.h" // for complete type TestB
const TestA & TestA::operator=(const TestB) { /* ... */ }
// B.cpp
#include "B.h"
#include "A.h" // for complete type TestA
const TestB & TestB::operator=(const TestA) { /* ... */ }
Please note that such a construction creates the curious design situation where any consumer of either TestA
or TestB
who wished to call the operator must always include both A.h
and B.h
, which is very granular, but also a bit unexpected. It might be worthwhile adding an intermediate header file for use by the client which includes both header files, or to add mutual inclusions (with guards!) to the header files themselves.
You cannot resolve this in the way you wrote it, because you have a flat-out recursive infinite dependence.
The way you usually do this is to pass the arguments by reference rather than by copy, since passing by reference does not require knowledge of the complete type:
const TestA & operator=(const TestB &);
^^^^^
vvvvv
const TestB & operator=(const TestA &);
Upvotes: 4
Reputation: 208353
There is no actual problem in those headers, as long as they only declare the member functions and don't provide definitions. That is, if the definitions for the member functions are in a .cpp file that includes both headers and that there are no calls to either function in the headers, it should work perfectly.
There is a common misconception that you cannot use anything that looks like value with a forward declared type, the fact is that you cannot create objects of that type or create member variables of that type, but you can declare functions that take or return those types by value.
You cannot, on the other hand, define or call those functions, since that would require the creation of an object of the incomplete type.
Upvotes: 1
Reputation: 32510
Forward declarations are only good for declaring pointers and references to the type ... they can't be used for actual copy operations as well as declarations of class instances as non-static class data members. If you attempt to-do so, the compiler will give you an error for an incomplete type, since there is not enough information present to give the compiler information on what the actual type is composed of (i.e., how large it is, etc.), so that it could construct the main class or determine how much stack space to allocate to one of the class' method arguments.
Upvotes: 0
Reputation: 37437
You pass references to the classes as parameters. This way, a class and its member functions can be declared without knowing about the other.
//TestB.h
class TestB; //Forward declaration for a later operator= in a centralised header
class TestA
{
const TestA&operator=(const TestB &); //defined in TestB.h
};
And:
//TestA.h
class TestA; //Forward declaration for a later operator= in a centralised heaer
class TestB
{
const TestB&operator=(const TestA *); //defined in TestA.h
};
After this, you'll have to include both TestA.h and TestB.h in both TestA.cpp and TestB.cpp files to be able to define these member functions.
Upvotes: 4