Class vs helper routines - C ++

I am new to C ++ and come from background C.

I am currently working on a C ++ project, and by adding code, quite often I find that I ask that I just have a set of auxiliary routines or create a dedicated class for them.

Any suggestions on this? I can see if there is an element of resuability of the code, or generality, then creating a class makes sense. But if, say, the code in the set of auxiliary routines is used only for the selected task for only one function, what would I get by putting them in classes?

I understand that my question is rather abstract and perhaps vague, but any suggestions / best practices would be appreciated.

Thanks.

+4
source share
8 answers

Use classes when you do object oriented programming, i.e. when some type of object is used , and not when you just write utility functions.

More specifically, when in C you will have

typedef struct { /*...*/ } Foo; 

with assortment

 Foo *make_foo(); void print_foo(FILE *, Foo const *); // etc. 

you must put functions that work with Foo objects in class Foo . But when you implemented a bunch of useful mathematical operations that only accept and return floating point numbers, they certainly make them stand-alone functions and consider using namespaces instead of classes to group them.

The great thing about C ++ is that it does not impose a class-based approach on you like Java does ; This is not suitable for every problem area.

+10
source

It depends on the features. If they manipulate a common dataset, it makes sense to put the data in a class and make them members. If they are more or less independent of each other, placing them in a class is actually misleading; he offers relationships that do not exist.

In any case, do not be afraid to use the free features when they are more suitable.

+8
source

In my opinion, in a good OO design, you should not create a helper class. Each class should represent some object in the real world and should contain methods that represent the actions that this object performs. In the real world, we have no action that is not associated with any object. Therefore, I believe helper classes or static methods are hell in developing OO :). It should be noted that if the class that you created does not represent any object of your system and is intended for internal use only (it is simply used in your methods and will not be represented in uml), it can be transferred to another submodule project.

+2
source

Here are a few reasons why using a class is useful:

  • You avoid name collisions with the class name.

  • A class name can simplify function names and / or make them more readable.

  • If your functions require enumerations, then the enumerations will be neatly packed with your functions.

  • If your function access constants, the constants will be packed into a class.

  • If you support support parameters (or in a future version), implementing them as non-static methods, multithreading is simplified.

+1
source

If functions do not support the internal state and are reentrant, I don’t see the point of defining a class with static members or creating class objects only to call methods β€” this will be meaningless typing.

+1
source

What is a class ?

In the strict sense, an OOP class is a collection of related data with methods for working with this data. However, C ++ is far from being a pure OOP language, and encapsulation is a much better goal, so that some kind of religious, over-senseless utopia.

What data should be placed in a class ?

The associated data should usually be related to each other, for example, the length of the buffer and the buffer associated with it belong to each other, since you cannot use a buffer without its length.

Encapsulation (and the Law of Demeter) will then report that they must be private so that class clients are not dependent on its internal representation. In practice, however, it is viable that some information should be open to the public directly in order to avoid creating many getters / seters functions (although they have their advantages).

At least, although the data that is associated with invariants (*) must be private so that these invariants can be respected.

What functions should be placed in a class ?

Any function that needs direct access to the private data of a class must be a class method. A notable exception are operators whose signature is corrected. This can be solved by giving them friendly access.

Corruption lies in the fact that any function that does not need direct access (since other methods provide sufficient information for its functionality) is better implemented as a free function. This increases encapsulation.

A typical example: std::string::find_first_of (and related) should be implemented as a free function.

What is a blob?

Sometimes you find that you have a bunch of related data, but without a strong invariant between each other, for example:

 struct State { Language language; Page currentPage; }; 

If you change the language, it does not change the page and vice versa. These two are just for convenience. This does not correspond to the class and is sometimes called blob due to its unstructured form. It no longer requires more encapsulation, and the methods are thus superfluous (although the constructor may help).


(*) On invariants

As explained, the length of the buffer is closely related to the buffer itself, they must be changed together. Therefore, there must be a buffer class that has two members: length and buffer, and which manages these two, so that the invariant that length is the length of buffer is always satisfied (with respect to external observers).

On the other hand, if you create an attribute std::string filename; and you hide it in BigObject , along with logmessage and logmessage , then you are doing it wrong. BigObject must have the Filename filename; attribute Filename filename; and allow it to the Filename class to maintain this invariant.

+1
source

These are several different types of encapsulation and abstraction that C ++ allows you to express more directly than C, but not hard rules.

Invariants

If you currently have a structure (or even some primitives that you usually go together), but want to enforce some invariants that simplify your code, there is a good argument for using a class with private data members that can support these invariants.

An obvious example is std::string compared to { char const *p; int length; } { char const *p; int length; } { char const *p; int length; } . With the second form, you need to manually process the (de) distribution, decide whether it is legal for p to be NULL, and make sure you check this everywhere, manually force nul-term if necessary, etc.

Interfaces and Inheritance

You can implement them in the C interface: ~ ~ structure containing pointers to functions, inheritance ~ = creating the "basic" structure of the first member of the "derived" and fun casting between them. Indeed, these mechanisms are widely used within C.

However, if you need run-time polymorphism, compiler-based support and submitting a virtual method in C ++ is usually much cleaner and clearer.


In addition, there are many situations that can be expressed in terms of classes, but not necessarily.

Collections of related functions and structures can be placed in a class, but you can also simply group them in a namespace and leave data in a public struct . Indeed, even if the data has invariants, minimizing the number of privileged methods and including other related logic in free functions is the best style (this reduces the number of place invariants that need to be checked or guaranteed).

Some types of variations are better expressed with compile time than run-time polymorphism (i.e. patterns). In this case, you do not need an inheritance relationship, because templates can use duck printing.

Dependency hiding is as easy to do with an opaque typedef pointer as it is with a pimpl or handle / body class, with the exception that the open external class needs to do something more to control the impl pointer's lifetime than shared_ptr or unique_ptr provides .

And, of course, some code is, of course, functional or procedural, and there is no use to teaching it in a class.

+1
source

I am in the same condition. I just came from the C world, and now I have been working with C ++.

My suggestion is to create a class and call its methods.

Maybe in the future someone might use the same class;)

-2
source

Source: https://habr.com/ru/post/1396808/


All Articles