4

I have a C++ component that contains important data that needed from various other components in my program.

The component might contain its own task or not. But in either case it will also hold the data in structs or classes.

The other components that will include the component in question might not need all the data from it.

For example:
We have a component options that contain contain some options/configuration for other components.
enter image description here

Some options might not needed from one component.

The question is whether the module options should be a class and make it public with extern keyword in the header file or just use plain free functions (getters)?

If options is an object. It will be only one object. There's no need for a second object to be created. So it's gonna be either a singleton or just a public object in the cpp file passed global with extern keyword in the header.

Editing my question to clarify a couple of things regarding the two possible solutions.

A class:

class options
{
  int getOption1();
  int getOption2();
  char getOption3();
  float getOption4();
  char * getOption5();
}

Free functions:

namespace options
{
    int getOption1();
    int getOption2();
    char getOption3();
    float getOption4();
    char * getOption5();
}

5 Answers 5

6

So, you have to decide between a singleton and a bunch of free functions in a namespace, with some dedicated global state either way?

First, why do you want a singleton?

If it is just to ensure they share the state, consider extracting it into namespace-level TU-internal variables, and make any functions you want static. No need to muck around with singletons, which are ill regarded due to blatant over- and mis-use, aside from mis-implementation.

Next, why a class at all?

This is not Java, you can have free functions and global state outside classes, perfectly hidden from the outside unless external linkage is requested. It has the advantage of easier extensibility, and unless you need to provide a specific interface (for static injection with templates or dynamic injection with inheritance), there is no downside.

This is actually the preferred way, absent reason to do otherwise.

2
  • 1
    If I choose to export everything with free functions getters. Where should I put all my data inside the cpp file? I mean, should I just use a struct to group all the data and use free functions as getters? Or a class with public members? Commented Feb 4, 2023 at 21:33
  • 1
    @SomethingBetter why do you keep asking whether you should make things more complicated than they need to be? Commented Feb 7, 2023 at 18:08
2

Assumed the free functions which belong to the same component have their own namespace, this is just a matter of taste. I am sure you won't find a hard, technical argument for or against those two approaches, they will both work and don't provide a huge difference in readability or maintainability.

So I would recommend you choose the variant which fits best to the programming style or "school of thought" of the overall system. If you prefer OO programming, use a class + single object. If you prefer hybrid style, or to use as few C++ language elements as required, use free functions. And if you don't have any preference, flip a coin.

0

There is not such a big difference between procedural and object oriented programming as you might think. I found a great definition here:

"Attributes and methods are basically variables and functions that belongs to the class.". So you can think of a class as an isolated piece of software, that communicates with the rest of your program through a well defined interfaces. Implementing the class will give you some overhead, but you gain better control of the things that happen inside your class. OO-programming allows to use simpler approaches (like class-global variables), that otherwise would lead you to a total desaster.

I found myself several time starting with a simple concept and writing just free functions (e.g. a fully procedural code). Over time, I found some "functional units" in my code, several functions and variables that applied to the same task like accessing a database or creating some graphics. To keep my code clean I then decided to put all those elements together in one class. Often I found this classes useful in other programs, and OO made it really easy to use the code again. But in any case, creating classes was far more effort than writing procedural code. On the other hand, this effort helped to prevent spaghetti code, which was a value on it´s own.

BR, Eckehard

1
  • I'm trying to avoid put everything into one class because it creates god objects Commented Feb 5, 2023 at 15:52
0

Classes should be used to organize your code, not as a "spagehtti container".

Each class should only apply to a single, relatively simple task, and often it is not a single class, but a hierarchy of classes you will use.

Assume you have a progam that displays - beside many other things it does - some graphics. So it could be a good Idea to put all your graphics functions together in a separate code module. One function paints a circle, the other a rectanlge.

Now you will find, that all your functions do very similar things, like open your graphics device, ceate some canvas and perform the painting. That is the time to create a "parent" class, that performs all the common stuff. All the childred will inherit the common stuff an will only need to do, what is specific for them. This saves a lot of redundancy and makes your code easier to maintain. But each class should be as simple as possible, one class - one task!

0

Using a class, i.e. an object, to hold the options has merit.

Disclaimer: Having Just One global state of the options at production runtime makes total sense, but ...

When you have a bunch of free functions that access some global state, this is the only way you can use that "options module", that is, it will always have exactly one global state and the interface does not allow for anything else. It is truly a singleton.

However, when you create an option class, where an object of this class type holds all options information, then -- for example in some (unit) tests -- you can instantiate as many of these Options objects as you want.

In the actual production code, the "singleton - ness" of the option can then be encapsulated in a single global getter options get_glob_options(); that can be used from different code parts, or you can decide to not do this and pass an options object along from some entry point (-> dependency injection).

So, in summary, I'd say if the information is "options like", that is it does not represent something truly unique to your process, then the class/object approach is "better".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.