I would like to know how legitimate and effective this is (in general, it is implemented and seems to work). C ++ language, yes.

For example, there is a large class that can be divided into modules. These modules, however, are rather strongly connected with each other, constantly invoke methods of each other, and so on. Let's say one performs, the other controls, the third serves. For the most part, this is for convenience, so as not to scroll through tons of code and not to look for some kind of functionality.

That is, the division into several classes is rather difficult, and you have to struggle with instances of these classes to achieve data unity in an already conventional large class ( static doesn’t fit at all: suddenly you have to run this large class in parallel, and then the data should not overlap, t Should there be different instances?). Besides, I don’t want anyone to see this or that functionality of these possible classes, besides who really needs to use their capabilities, and this is the maximum - not further than the boundaries of this large class, but in fact - not further than the boundaries of areas the visibility of one or another of its modules that would become classes (a little later about it). I think you can do it, but a chore.

But in different modules (for example, we have already broken them into different .cpp-files) different data fields, different method descriptions will be needed. And in order not to throw out a whole stop on them from the same header file, it would be possible to divide it into different header files, each connecting to its own module. Some fields and some function prototypes will appear in several header files, but the functions themselves will be implemented only somewhere in one place.

Something like this means:

 // Ah #pragma once class MyClass { MyClass(); void func1(); void func2(); } * * * // A.cpp #include "stdafx.h" #include "Ah" MyClass::MyClass() { /* какой-то код */ } MyClass::func1() { func2(); } // func1 прекрасно видит func2 * * * // Bh #pragma once class MyClass { void func2(); void func3(); } * * * // B.cpp #include "stdafx.h" #include "Bh" MyClass::func2() { /* какой-то код */ } MyClass::func3() { func1(); } // нет, он не будет компилироваться, func1 ему не известна 
  • 6
    If you have so many methods in a class that you even want to classify the class declaration into pieces, maybe you still have to work and refactor it into 10 small classes? The fact that different pieces are strongly intertwined is some kind of spaghetti logic. Try to simplify the structure of your code. - VladD
  • If you try, you can break, but I have already spoken about the problems that arise: the unity of data and the availability of functionality. The data should be uniform for any one line of events so that there can be several of these lines, and the data between them does not overlap (no static, that is). We'll have to create some other mini-class that will control all this and in which all the work will take place (it causes everything else). Secondly, accessibility to these small classes should be seriously limited, their interfaces should not be accessible to everyone. - brenoritvrezorkre
  • 2
    Yes, it is logical that you need to do small-helper-classes. Council nevertheless to paint what is now and what you strive for in a visual form. Almost certainly, an understanding of how best to do will come. > their interfaces should not be accessible to all; well, in C ++ there are such mechanisms. Start from the fact that you can use namespaces and nested classes, to limit the availability of class members and use friendship (friendship is magic (r)!) - gecube
  • eight
    All these problems are a trifle compared to another problem: you have a class with a million responsibilities . - VladD
  • Isn't a direct answer to the question simply “no, it’s impossible to do so”? Those. Is it impossible to break the class declaration into different headers? - andy.37

1 answer 1

I close the question, because no one will answer. There is a discussion above, from which it follows that:

  • It works;
  • But this can lead to confusion with headers;
  • This means that there is a class with a large number of responsibilities, which seems to many unnecessary, and in the development team such code would cause a corresponding misunderstanding.

Refactoring causes two problems:

  • Working with instances: the algorithm must maintain data integrity, but only within a single line of common events, and these "rulers" may be somewhat parallel;
  • Accessibility: class interfaces should be invisible from the outside, but accessible where you really need it.

I solved these problems (I hope) in this way:

  • One class was as it was and remained, but now the subclasses responsible for modularity and which are nested into each other are allocated;
  • Work with them happens through pointers, except when accessing static methods;
  • Each nested module is declared in the private zone of the class, and something else can also be attached to this module;
  • Because of this, there are problems associated with the overhead of nesting and the need to schedule a code in the style of А::B::C::func() {...} ;
  • However, this solves the problem of accessibility from the outside;
  • But at the same time, there remains the problem of undesirable accessibility from within, since nested classes apparently can refer to a private bordering class, which is not specified in the standard and is not recommended;
  • All data is stored in a storage with get/set methods that are a nested class that is not accessible from outside;
  • Instances of this repository are alternately transferred from class to class: each time in the constructor of the bordering class, the parameterized constructor of the nested class is called, into which the repository copy is dropped via a pointer;
  • In the destructor, everything is destroyed accordingly.

As a result, the code has changed in volume:

  • Header files have decreased due to the absence of the need to register matching fields and methods;
  • A separate module with data appeared;
  • The implementation files have noticeably increased, since now the work is done through pointers or through a combination of them, and the transfer of the universal pointer void* to some data in the storage get method requires the subsequent static_cast<type*>(void* ptr) .

To be honest, I was expecting an answer, as my initial version will be processed by the average msvc (and other compilers) and linker, whether everything looks really like what I had in mind or not in terms of build and other things, but alas. And the indications of "spaghetti" are relatively really closely related to each other controller, processor and "servant in the process of work", representing certain aspects of a single whole - I do not think that they were sufficiently relevant and related to the topic of the question asked.

  • To be honest, I don’t care about negative assessments, so you can at least set the alarm. - brenoritvrezorkre