Use details based on C++ type redefinition

  • 2020-04-01 23:36:10
  • OfStack

During these days, I encountered a C++ compilation error (I used Visual C++ 7.0), saying that there was a class duplicate definition, think carefully about our project is also made several releases, the internal code should not have such a low-level error, the type to the duplicate definition, check the result as I expected. Just like that, I couldn't find the reason left or right, and was stuck there by a compilation error. In my concept, the level of program error is: compile error - > Link error - > Logic error, which is the lowest level. At this point I looked at the error and found that the duplicate definition was caused by the inclusion of the same header file from two different paths. My colleague also suggested trying to open the project from another path. This is a bit of a mouthful, and the fact that this error is a bit of a twist, let me explain it in terms of the redefinition of the type in different cases.
I've summarized three types of redefinition cases.
There is no #pragma once indicator in the header.

Type1.h:
//#pragma once
class Type
{
};
Main.cpp:
#include "Type1.h"
#include "Type1.h"
int main(int argc, char *argv[])
{   
return 1;
}

#pragma once ensures that this file is compiled only once. If you don't include this in type1.h, then include type1.h twice in main.cpp, which is equivalent to defining the Type class twice in main.cpp.

2. The same type is defined in two different header files (both have #pragma once)

Type1.h:
#pragma once
class Type
{
};
Type2.h:
#pragma once
class Type
{
};
Main.cpp:
#include "Type1.h"
#include "Type2.h"
int main(int argc, char *argv[])
{   
return 1;
}

Here, main.cpp contains both type1.h and type2.h header files. Although both header files have #pragma once, because they are different files, the precompiler will put the definition of Type class in main.cpp twice.

Contains the same header file from two different paths
While the first two are more common and easier to solve, the third is less common and typically occurs when there is a virtual disk. (so as to do from two different paths containing the same header file), the other will appear at what time, I have not thought, know the friend :). Here's my analysis:
1) VC project in D:\Test directory.
2) Map virtual disk X to D:\Test.
Unfamiliar users can follow this operation: start - > Run - > In the run window enter: CMD - > Enter in the CMD window:
Subst X: D: \ Test
3) The project has the files type1.h, main.cpp

Type1.h:
#pragma once
class Type{};
Main.cpp:
#include "Type1.h"
#include "X:Type1.h"
int main(int argc, char *argv[])
{   
return 1;
}

Here we have two header files in main.cpp, which in essence correspond to the file type1.h on the physical disk D:\Test, which is the same file. But under different operation, VC has different interpretation to it. #include "X:\ type1.h "USES the absolute path, so there is no objection, but #include" type1.h "has some changes:
The & # 8226; If I open the project from D:\Test\, then #include "type1.h" is actually #include "D:\Test\ type1.h"
The & # 8226; If the project is opened from X:\, then #include "type1.h" is interpreted as #include "X:\ type1.h"
4) Open the project under D:\Test, compile, Type Type duplicate definition error occurs
In this case, main.cpp is precompiled as:

Main.cpp:
#include "D:TestType1.h"
#include "X:Type1.h"
int main(int argc, char *argv[])
{   
return 1;
}

#pragma once only guarantees that this file will be compiled once. Here, VC considers it to be two different files, so both files must be compiled.
Of course, if you open the project from X:\, the VC will think it's all from X:\ type1.h to include this file, and #pragma once does the job, so there's no type redefinition

Four,
I tested the third case in VC7, VC8, and Dev C++, and found that only Dev C++ could compile. This may be because Microsoft VC's # pragma once is not smart enough to be easily blinded by Windows' virtual disk to its essence (just to guess, maybe VC is doing this for other purposes).

Because in the engineering development of slightly larger, we usually use virtual disk to convenient work, one is the quick access, simplifies the path, because many people coordinated development, we hope that we usually source code path is the same, but we should not force everyone put the source code to die in a directory, then put your source code path is mapped to a virtual disk (such as unified as X:) you can put everybody's unified code path. On the other hand, with the virtual disk, there is a condition for the occurrence of type redefinition. Here are two solutions I came up with:
1) discard #pragma once, which is ancient but combines stability and portability

#ifndef _XXX_H
#define _XXX_H
//...#endif

To ensure that the header file is only compiled once. This contains two identical files, or contains two different files, or contains two files the same but different path file, as long as _XXX_H been defined, won't compile the compiler (but here we want to guarantee the uniqueness of _XXX_H, if two different header file with the same _XXX_H, will be a problem)
2) when including header files, do not use an absolute path, even if it is the absolute path of the virtual disk.

Related articles: