E
E
Eugene Ordinary2016-12-15 23:35:45
Programming
Eugene Ordinary, 2016-12-15 23:35:45

How to hide the definition of auxiliary types in C++?

The module defines the class MyClass1 using the auxiliary structure MyStruct2, which itself is not used anywhere outside the module.

class MyClass1 
{
  MyStruct2 member;
  ... 
}

Is it necessary to place the full definition of MyStruct2 before the definition of MyClass1 in the header file? If it is mandatory, then is it possible to set MyStruct2 at least with the help of a prototype. On the one hand, the compiler must know MyStruct2 in order to correctly understand the definition of MyClass1, but at the same time, the content of .h is logically a module interface and you don’t want to include unnecessary things there.
In general, I can’t figure out how to organize modules. The module has functions that should be available from the outside, and there are auxiliary ones. There are also main and auxiliary types. How to arrange all this correctly, what to write in .h, what in .cpp.
Is this diagram correct?
.h
typedef ... LocalType1;
...
class ... LocalClass1 {...};
...
typedef ... GlobalType1;
...
class ... GlobalClass1 {...};
...
GlobalFunc1(...);

.cpp
LocalFunc1(...);
...
LocalFunc1(...)
{
 ...
}
...
GlobalFunc1(...)
{
 ...
}

Answer the question

In order to leave comments, you need to log in

3 answer(s)
E
Evgeny Shatunov, 2016-12-16
@evgeniy8086

In general, your question does not have an exact answer, because. the question touches upon topics of colored pencil taste and is merely rhetorical.
In addition to all this water that I have outlined below, it is also very worth reading the "SF: Source files" section of the official guideline:
https://github.com/isocpp/CppCoreGuidelines/blob/m...
(I strongly advise you to study the entire guide from cover to cover)
On the first question, briefly: if the type is used by value, the full type declaration is required, otherwise Forward declaration can be dispensed with.
A little more:
There is such a principle of project formation, when each header file provides complete information about dependencies. Forward declaration in this case is either prohibited or strongly condemned. Each header file must include the header files of all dependencies. And the source code file must include exactly one header - the one whose interface is implemented in the source code.
This allows you to immediately see all the dependencies of the code, not to worry about the placement of files, not to worry about transitive dependencies, just not to worry, and also significantly rake at compile time. Especially if only #include "" is allowed in the project, and #include <> is condemned.
As an example, you can read UE4.
There is another principle of project formation, when the file structure reflects the macro level of the project architecture. Say, if the project is based on subsystems or layers, each layer (subsystem) is represented by exactly one header master file and its own separate folder in the file system. Inside this folder are all the internal header files of the subsystem. None of the internal header files contains any dependencies, only the declaration of its interface. All dependencies (FD, other subsystems or layers, system headers, etc.) are described only by the master file, which also includes all internal headers in the required sequence. Other subsystems, as well as the source code of the subsystem itself, include only the master file.
This allows you to remove all the husks from internal headers and focus their text exactly on the interface declaration. On the other hand, for the sake of using some small tip, you always have to connect the entire subsystem, because. internal headers cannot be included due to the rules of project formation and because their dependencies are unclear.
In both principles, one very important rule applies: One class - one set of source code with the name of the class itself. This, one might say, is the most basic principle of project formation. Classes with an invariant and rich functionality must be declared each in its own separate header, with the class name. The description of the functionality of each such class should be in its own source code file with the name of the class being described. Sometimes you even need several source code files per class, because the class performs too many functions, but you can’t separate it.
This principle often leads to a circular dependency problem where two classes refer to each other and each header needs to include a second header. In this case, either the redesign of classes to weaken dependencies, or the Forward declaration as the lesser of the evils, helps.
From the compiler's point of view, there is only one file format - the source code format, which it needs to process.
From a human point of view, there are not two file formats, but 3 or 4:
If with "human formats" everything should be well understood, then with the file format for the compiler it is worth understanding one subtlety - all these human chess with tambourines and division into files should add up to the form that is as convenient as possible for compilation. The fewer identical #includes, the better. The fewer #includes in general, the better. Broadcasting is no easy task.

A
Adamos, 2016-12-16
@Adamos

class MyClass1 
{
  MyStruct2 member; // компилятору необходимо полное описание структуры - она является частью класса (в частности, влияет на размер объекта в памяти)
  MyStruct2 *member; // компилятору не требуются подробности. Если этот член не используется вне класса - описание структуры спокойно может лежать только в cpp-файле этого класса, больше оно никому не понадобится.
  ... 
}

J
Johanga, 2016-12-16
@johanga

class MyStruct2; // forward declaraion
class MyStruct1
{
   MyStruct2 member;
};

can interface or pImpl

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question