A brief analysis of the application and trap of pre declaration in C++

  • 2020-04-02 01:13:20
  • OfStack

The use of preposition declarations
Friends with some experience in C++ development might encounter A scenario in which two classes A and B are strongly coupled, with class A referring to B's object and class B to A's object. Well, it's not hard. My first instinct was to write code like this:


// A.h
#include "B.h"
class A
{

public:
    A(void);
    virtual ~A(void);
};
//A.cpp
#include "A.h"
A::A(void)
{
}
A::~A(void)
{
}
// B.h
#include "A.h"
class B
{
    A a;
public:
    B(void);
    ~B(void);
};
// B.cpp
#include "B.h"
B::B(void)
{
}
B::~B(void)
{
}

Okay, done. Compile a.cpp. No pass. Recompile b.pp, still not pass. The compiler gets confused, the compiler goes to compile A.h, finds out it contains B.h, goes to compile B.h. When compiling B.h, it was found that A.h was included, but that A.h had already been compiled. A compilation error is better than a dead loop. And then we see that we're using the definition of A, and here we go, the definition of A is not compiled, so we can't find the definition of A, so we compile something wrong. The prompt message is as follows:
1 > D :/vs2010/test/test/a.h(5): error C2146: syntax error: missing '; 'before the identifier' b '
1 > D: / vs2010 / test/test/a.h (5) : error C4430: missing type specifiers - int assumed. Note: c + + does not support default - int
1 > D: / vs2010 / test/test/a.h (5) : error C4430: missing type specifiers - int assumed. Note: c + + does not support default - int
So what? Yes, C++ provides us with predeclarations. What is the preposition statement? For example, I want to build a house, not just a house, but a CBed. But the house is not built, always can't buy a bed first, the size of the bed I set, another day to buy. First I have to build the house well. When I build the house, I will leave a place for the bed. When the house is finished, I will decide what kind of bed to buy. Pre-declaration is when I declare a class (CHouse), I use the definition of another class (CBed), but CBed is not defined yet, and I don't need the definition of CBed first, just know that CBed is a class. Okay, so I'm going to declare the class CBed, which tells the compiler that CBed is a class (no header file with CBed) :

class CBed;

Then in the case of CBed in CHouse, the pointer type of CBed is used (because the pointer type is fixed in size, but the size of CBed can only be determined by knowing the definition of CBed). By the time you implement the CHouse definition, you will have to know the definition of CBed, which is just to wrap the header file for CBed.

Front-facing declarations are sometimes useful, such as when two classes are interdependent. There are also front-facing declarations that reduce the level of header file inclusion, reducing the possibility of errors. The above example.


// House.h
class CBed; //When building a house son: do not buy now, must buy a bed
class CHouse
{
    CBed* bed; //I'll make room for the bed
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed();
};
// House.cpp
#include "Bed.h"
#include "House.h" //When the house begins to decorate, buy a bed
CHouse::CHouse(void)
{
    bed = new CBed(); //Put the bed in the house
}
CHouse::~CHouse(void)
{
}
void CHouse::GoToBed()
{
    bed->Sleep();
}
// Bed.h
class CBed
{
public:
    CBed(void);
    ~CBed(void);
    void Sleep();
};
// Bed.cpp
#include "Bed.h"
CBed::CBed(void)
{
}
CBed::~CBed(void)
{
}
void CBed::Sleep()
{
}

The trap in the preposition statement
Note the pitfalls:
1, CBed * bed; You must use Pointers or references
Quoted version:

// House.h
class CBed; //When building a house son: do not buy now, must buy a bed
class CHouse
{
    CBed& bed; //I'll make room for the bed
    // CBed bed; //  Compile error 
public:
    CHouse(void);
    CHouse(CBed& bedTmp);
    virtual ~CHouse(void);
    void GoToBed();
};
// House.cpp
#include "Bed.h"
#include "House.h" //When the house begins to decorate, buy a bed
CHouse::CHouse(void)
    : bed(*new CBed())
{
    CBed* bedTmp = new CBed(); //Put the bed in the house
    bed = *bedTmp;
}
CHouse::CHouse(CBed& bedTmp)
    : bed(bedTmp)
{
}
CHouse::~CHouse(void)
{
    delete &bed;
}
void CHouse::GoToBed()
{
    bed.Sleep();
}

2. The CBed method cannot be used in the CHouse statement
The undefined type CBed is used;
Bed - > The left side of Sleep must point to the class/structure/union/generic type

class CBed; //When building a house son: do not buy now, must buy a bed
class CHouse
{
    CBed* bed; //I'll make room for the bed
    // CBed bed; //  Compile error 
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed()
    {
        bed->Sleep();  //Compilation error, the bed did not buy, how can sleep
    }
};

3. Call the destructor of CBed before the definition of CBed

// House.h
class CBed; //When building a house son: do not buy now, must buy a bed
class CHouse
{
    CBed* bed; //I'll make room for the bed
    // CBed bed; //  Compile error 
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed();
    void RemoveBed()
    {
        delete bed; //I don't need the bed. I'm taking it out. How can I take it apart if I haven't bought it yet?
    }
};
// House.cpp
#include "Bed.h"
#include "House.h" //When the house begins to decorate, buy a bed
CHouse::CHouse(void)
{
    bed = new CBed(); //Put the bed in the house
}
CHouse::~CHouse(void)
{
    int i = 1;
}
void CHouse::GoToBed()
{
    bed->Sleep();
}
// Bed.h
class CBed
{
    int* num;
public:
    CBed(void);
    ~CBed(void);
    void Sleep();
};
// Bed.cpp
#include "Bed.h"
CBed::CBed(void)
{
    num = new int(1);
}
CBed::~CBed(void)
{
    delete num; //Can't call
}
void CBed::Sleep()
{
}
//main.cpp
#include "House.h"
int main()
{
    CHouse house;
    house.RemoveBed();
}

The front declaration resolves the interdependence of the two classes
Here's the answer to the first question:

// A.h
class B;
class A
{
    B* b;
public:
    A(void);
    virtual ~A(void);
};
//A.cpp
#include "B.h"
#include "A.h"
A::A(void)
{
    b = new B;
}
A::~A(void)
{
}
// B.h
class A;
class B
{
    A a;
public:
    B(void);
    ~B(void);
};
// B.cpp
#include "A.h"
#include "B.h"
B::B(void)
{
    a = New A;
}
B::~B(void)
{
}

Application of predeclaration in friend metaclass methods
The C++ Primer 4Edition says in the friends section of A class that if A member function of another class B is declared as A friend function F in the declaration of A class A, class A must know the definition of class B in advance. The member function F of class B declares that if class A is used as A parameter, then the definition of class A must also be known, and the two classes are mutually dependent. To solve this problem, you must use the predeclaration of the class. Such as:

// House.h
#include "Bed.h"
class CHouse
{
    friend void CBed::Sleep(CHouse&);
public:
    CHouse(void);
    virtual ~CHouse(void);
    void GoToBed();
    void RemoveBed()
    {
    }
};
// House.cpp
#include "House.h"
CHouse::CHouse(void)
{
}
CHouse::~CHouse(void)
{
    int i = 1;
}
void CHouse::GoToBed()
{
}
// Bed.h
class CHouse;
class CBed
{
    int* num;
public:
    CBed(void);
    ~CBed(void);
    void Sleep(CHouse&);
};
// Bed.cpp
#include "House.h"
CBed::CBed(void)
{
    num = new int(1);
}
CBed::~CBed(void)
{
    delete num;
}
void CBed::Sleep(CHouse& h)
{
}


Related articles: