Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ classes prototype conflict

Tags:

c++

class

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!

like image 793
SSight3 Avatar asked Sep 07 '11 15:09

SSight3


2 Answers

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.

like image 165
Didier Trosset Avatar answered Oct 03 '22 18:10

Didier Trosset


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 &);

like image 43
Kerrek SB Avatar answered Oct 03 '22 17:10

Kerrek SB