C + + about declarations, definitions, class definitions and the role of header files to prevent header files from being repeatedly referenced in the same compilation unit without naming space

Time:2022-1-20

 1. Compilation unit, one CC, or CPP as a compilation unit Generate o

2. Definitions and declarations of common data types and functions (class functions are the same)

  • extern int x; // The variable is declared and does not actually assign an address,No actual object code was generated

      void print(); // Function declarationNo actual object code was generated

Such as int x; int x = 3 ; void print() {}; // All definitionsThe actual object code is generated

  • The declaration does not produce the actual object code. Its function is to tell the compiler that OK, I will have the definition of the X variable and print function behind the compilation unit or other compilation units. Otherwise, the compiler will report an error if it finds that the program uses X and print without the previous declaration. If there is a declaration but no definition, an error will be reported when the link is not defined.
  • The more common is that I’m at source Print () is called in CC, and head. Print () is declared in H, while source Include in CC

head. H so that there is a print declaration, which can be compiled. However, if there is no definition of the print function in all compilation units, the chain will be broken

When you pick it upsource. The O unit will go wrong because it tries to use the print function but cannot find the definition of print.

        //head.h

       void pirnt();

       //source.cc

       void foo() {

            print();

       }

  • Since declarations do not produce actual code, there can be multiple duplicate declarations.

       //source1.cc

       extern int x;

       //source2.cc

       extern int x;

Even the same compilation unit can have multiple duplicate declarations

      //source1.cc

      extern int x;

      extern int x;

Ordinary variable definitions and function definitions are not allowed.

3. Duplicate name symbols within the same compilation unit are blocked during compilation, and duplicate name symbols between different compilation units will not be sent until the linker

present。 

If you’re in a source1 CC medium

     //source1.cc

     int x;

     int x;

Int x occurs twice; int x; That is, the definitions of two X will compile and report errors, and X will repeat the definitions.

If your

     //source1.cc

     int x;

     //source2.cc

     int x;

     g++ –o test source1.cc source2.cc

Then there will be no error in the compilation process. In the linking process, because there are two local X in the object code, the linking error will occur and X will be redefined.

Different programmers may write different modules, which is easy to happen. How to avoid it? Namespace can avoid duplicate names.

Google programming specification encourages the use ofUnnamed space

     //source1.cc

     namespace {

     int x;

     }

     //source2.cc

     namespace {

     int x;

     }

OK, there will be no link error now, because the two X’s don’t have the same name. Of course, for this simple example, it’s only in source1 Use an unnamed namespace in CC

Avoid link travel.

//Note

     //source1.cc

     namespace {

     int x;

     }

    //source1.cc

    static int x;

What’s the difference? It looks the same. The difference is that x in the unnamed space still has external links, but because it is unnamed, other units can’t link to it. If

   namespace haha{

   int x;

   }  

You can use haha:: X to access it in other units, and static cannot be linked to it because it is an internal link feature.

 

I remember a colleague asked me why I used it in the programanonymouse namespace, after thinking about it, I replied that it is actually to maintain locality (this is also my purpose), and then someone said why notstaticWell, it seems that there is no difference between these two things at first glance. I googled and found that one reason is that members in anonymous namespace have external links, but they can never be linked by external links! AndstaticIt is clear that there is no external link at all! At this time, there is a problem. The untyped parameters in the template must have external links, otherwise the compilation cannot pass; For example:
template
class Foobar
{};

namespace
{
void abc()
{
wcout<};
}
static void efg()
{
wcout<};
int _tmain(int argc, _TCHAR* argv[])
{
Foobarxyz //! ; This line can be passed
Foobarrst; //! Note that this line does not compile
return 0;
}
Others believe that anon is usednamespaceBetter, becausestaticThe way is criticized by the C + + 98 Standard. Ha ha. Generally speaking, you can use anonynamespacereplacestatic

 

4. About header files.

     //head.h

     int x;

     //source1.cc

     #include “head.h”

     //source2.cc

     #include “head.h” 

The header file is not compiled The reference include “head. H” in CC is actually to include head. H during precompiling Insert the contents of H into CC.

So if the above example

         g++ –o test source1. cc source2. CC, you will also find the repeatedly defined global variable x during the chain.

Therefore, variable definitions, including function definitions, should not be written into the header file, because the header file is likely to be multiple CC reference.

So if my head H is written as follows. Does it prevent the redefinition error of X’s link?

     //head.h

     #ifndef _HEAD_H_

     #define _HEAD_H_

     int x;

     #endif

     //source1.cc

     #include “head.h”

     //source2.cc

     #include “head.h” 

    Now whetherg++ –o test source1.cc source2.ccThere is no question. The answer is No.

      All header files should be added #ifndef #endif as aboveYes, but its role is to prevent header files fromSame compilation unitRepeated references.

That means preventing possible

     //source1.cc

     #include “head.h”

     #include “head.h”

In this case, of course, we will not take the initiative to write the above form, but the following situations are likely to be sent

     //source1.cc

     #include “head.h”

     #inlcude “a.h”

     //a.h

     #include “head.h”

In this way, the header file of the same compilation unit is repeatedly referenced inadvertently, so soruc1 CC, there are two int x; definition.

But for different compilation units, source1 cc,source2. CC they all refer to head H, even if #ifndef #endif exists.

5. Declaration and definition of classes.

class A; / / class declaration

Class declaration, like ordinary variable declaration, does not generate object code, and can be repeated in the same and multiple compilation units.

   class A {

   }; //Class definition

The definition of class is a little special. You may wonder why you can’t put int x; Such variable definitions are placed in H (see 4), but you can put

What if the class definition is repeatedly referenced in the header file? At the same time, the function of a class that is not an inline definition (except that the function written in the class definition is inline) cannot be written in the

In header fileYeah.

This is because the definition of a class only tells the compiler how the data format of the class is and how much space the object should occupy after the instance.

The definition of a class does not produce object code. Therefore, the only difference between it and the declaration of ordinary variables is that it cannot appear multiple times in the same compilation unit.

  //source1.cc

   class A;

class A; / / duplicate class declaration, OK

   class A{

   };

   class A{

   };       

   class A{

       int x;

}; / / if a class is defined repeatedly in the same compilation unit, an error will be reported when compiling, because the compiler does not know that in this compilation unit, a; What kind of A

//If class a {}; Defined in head h. Andhead. H no

//#Ifndef #endif is likely to have compilation errors with duplicate class definitions in the same compilation unit.

 

However, in different compilation units, classes can be defined repeatedly because the definition of classes does not produce actual code.

  //source1.cc

  class A{

  }

  //source2.cc

  class A{

}/ / duplicate class definitions for different compilation units. OK. So the class definition can be written in the header file!

                                

      //source1.cc

      class A{

     

      }

      //source2.cc

      class A{

          int x;

}/ / different compilation units, OK

 

   6.summary

1. Write variable declaration, function declaration, class definition and inline function in the header file. Do not appear variable definition. Class function is not inline definition and function definition

Righteousness.

NamelyDo not appear in the header file that may produce object codeDongdong.

2. In order to prevent repeated references to header files within a compilation unit, all header files should be added with #ifndef #endif

3. Encourage in Using unnamed namespace in CC can effectively prevent naming conflicts between different compilation units.

4. For a more professional and detailed introduction, you can see the first chapter of < >, which will have an extremely good and complete introduction.

Mentioned thereinClass is defined to have an internal link propertyYes, that is, it is not a declaration

It cannot be repeated in the same compilation unit, but it has an internal link (the so-called internal link refers to the name for theThe compilation unit is local and will not be the same as other compilation units when linking

Name ofName conflict)Therefore, if a class is to be used outside a single compilation unit, it must be defined in a header file.

For statements and definitions, the definitions given in the book are:

A declaration introduces a name into a program, and a definition provides a unique description of an entity (e.g., type, instance, function) in a program.

5. The first article above is not very accurate, according to the statement in < >

            Theoretically, you can put everything with internal links in the header file, including the definition with internal links。 as

            static int x;

            static void print() {};

ButThis is not advocatedBecause every file that contains this header file CC corresponds to opening up a space to store this x, that is, static int x is introduced into different compilation units; Because they are internal links, they do not affect each other.

Even if you use namespace, such as

Yes H medium

           namespace myspace {

                static int x;

           }

Different The header file is introduced in the CC file, and is invoked in its own compilation unit.MySpace:: X is also different and does not affect each otherof

Mentioned in the book

const int width = 3; / / see page 23 of the book

Such const variables should also avoid appearing in the header file, but they are similar to those in the previous C language

In header file

            #define width  3

It’s still very common. Do you want to be here

. h medium

            extern const int width;

In. CC

             const int width = 5;

It’s OK, but it’s troublesome. I think it’s It’s not a big problem to define const int width = 3 in H. won’t the compiler do some special processing optimization and allocate a separate space for each unit?

However, you can also use the following methods in Declare a batch of const variables in H. Note that unlike ordinary static variables, class members are static variables and static functions have external links. If

static const  int  SUCCESS = 0; , Success is not const but static int, so it cannot be initialized in the class (compilation error). It needs to be initialized in a certain class CC file, because it has external links. (in the Google programming specification, it is mentioned that global variables of class type are prohibited, static member variables are regarded as global variables, and class types are also prohibited)

 

    class code   

    {

public:

    static const result_code SUCCESS = 0;//program ended successfully

    static const result_code INVALID_ADDRESS = 1;//wrong addres

    static const result_code READ_FAIL = 2;//cannot read

    static const result_code WRITE_FAIL = 3;//cannot write

    static const result_code UNKNOWN_ACTION = 4;//dunno…

    static const result_code NOT_FOUND = 5;//key not found in paragraph

    static const result_code NO_WRITE = 6;//no write since modification

    static const result_code SYNTAX_ERR = 7;//command syntax error

    static const result_code EMPTY_CLIP = 8;//the clipboard is empty

    };