When to use classes in C++?

Hi all

This is probably a bit of an open question, and possibly one that could be answered on stack overflow however I thought given the number of people here experienced in embedded C++ it might be an ok place to start.

My background in embedded programming is in C, at university there wasn’t a lot of emphasis on OO for embedded although I did have some background in Java OO programming.

Recently I’ve found my programming skills pushed to the limits as it seems most text books don’t really talk about how to structure large programs. One of these issues for me is when to bother putting a ‘library’ or ‘module’ into a class or when to simply use the old method of C which was to declare all public functions in the header file.

I notice the majority of libraries available in Particle build use the C++ class methodology, I understand one of the benefits of this is to provide clarity in terms of restricted access i.e.declaring members private/public/protected. What other significant reasons are there for this?

At the moment I’m trying to figure out how to create a class (if it should be a class) of functions specific to communicating with an external piece of hardware. There will be multiple cpp files requiring access to these functions, hence by definition it will need to be a ‘global’ object. In this case, should each cpp file that needs access contain a separate constructor? To me this seems non-intuitive as the class describes an implementation to communicate with a single piece of hardware and hence only one object should be required. This has taken me to the concept of the ‘Singleton Pattern’ which delves even further into programming philosophy.

I suppose where I’m coming from is, OO programming was always described to me in terms of abstract concepts such as creating a ‘student’ object where you may want to do things like view age, change grades etc. or create ‘new’ students. This whole concept doesn’t make as much sense to me when viewed from an embedded world, where classes and objects in this context seem to very often only be used once.

If anyone could shine some light on this it would be hugely appreciated, I have spent considerable time trying to enlighten myself on other forums but I’m not quite there yet!

Hi @G65434_2, thanks for the post! Could you explain, in rough psuedo-code what you are to do? I have a general idea of what you are asking but I think things would be whole lot clearer with an example :slight_smile:

1 Like

Thanks @harrisonhjones

Suppose we had an implementation designed to control an LED, there is only one LED and as such only one object is required. (In the real world it’s probably unlikely that you would make a separate class just for an LED control but just for arguments sake).

LEDControl.h :

class LEDControl {

public:
  void lightOff();
  void lightOn();
  void setBrightness(uint8_t value); 

private:
  void setDutyCycle(uint8_t duty);
};

(The implementation in LEDControl.cpp is omitted)

For example here we can turn it on, off and change brightness. The setDutyCycle method for example could be private to the class as it is used in the setBrightness method but needn’t be publicly accessible.

Say for example we needed to control this LED both in main.cpp and another file, say peripherals.cpp.
In the past typically what I would have done would be just to create the implementation in a .c file and add the public methods, lightOn(), lightOff() and setBrightness() to the header, i.e. LEDControl.h and include this header in both main.cpp and peripherals.cpp.

My question is, is there any benefit for a module like this to be contained within a class? There will only ever be one LED. I can see where this might be useful if there were multiple LEDs and the constructor took a parameter of which output they were connected to (D1, D2 etc.) then multiple objects could be created and the power of OO would come into play. However, if you’re writing a library for a piece of hardware that will never need to be created twice, is there any benefit in structuring the library within a class?

My last question is, if there is benefit, how should main.cpp and peripherals.cpp gain access to the class functions? Should they both include a constructor for the LEDControl class? Or should the LEDControl object only be created once in main.cpp and then somehow passed to the peripherals.cpp file?
I’ve heard of people creating dedicated files, global_objects.cpp and global_objects.h for this purpose but it seems perhaps overkill?
Using multiple constructors to gain global access to the LEDControl members doesn’t make sense to me as there is only one LED…

Any thoughts are much appreciated!

Hi @G65434_2

Your proposed class has no data members, that is, it is just a bag of related functions. That is why it probably “feels” like it is overkill. Imagine a different class that had say increment and decrement methods and so the class needed to remember the current brightness level. Then it would “feel” more like a proper container for the data and the behavior (code) you wanted.

Object lifetime is an entire subject on which books could be written. In small embedded processors like Particle, the best practice is to statically allocate whenever possible so that heap fragmentation does not occur. This leads to some slightly painful ways of working with globals, but that pain really derives from the way that memory management on the platform has to inform design.

I think of it this way: we only really have two tools for organizing things–abstraction and hierarchy. Classes can provide one or both these, but just like when organizing your kitchen cupboards, you have to want it to be organized.

If you are OK with a random stack of pots and pans but you know where everything is and it functions well for you, that seems fine to me. If on the other hand you like everything in its place with labels and drawer organizers, then classes might be for you. There is no single right answer.

When projects get big and lots of people work on them at the same time, the organization brought by a class structure and hierarchy is just about required to keep everyone sane. The work can be partitioned and each class can handle its particular “concerns.” Separation of concerns is a hallmark of good design in my experience.

5 Likes

Awesome reply thanks @bko, your time is much appreciated.

Fair comment about my sparse example, so obviously in a non class example remembering current brightness level etc. could be achieved via either a global variable within the implementation or a static variable at function scope. I’m aware of the issues with globals, so are you suggesting here that it’s ‘cleaner’ (in general) to declare variables within a class (probably statically in this case) than using the methods suggested above?

Having understood the rest of your comment I take it it’s better (and again I say ‘in general’ as I know there is no single answer for this) to declare objects on the stack:

LEDControl led;

However, what I take from some internet research is that it’s generally better to allocate objects to the heap if they are going to be used for the life of the program (which for arguments sake the ‘led’ object will be).

Interestingly I’d agree with your comment ‘books could be written on object lifetime’ as I’ve seen some very detailed explanations of this which claim to only touch the surface, it interests me however as surely many programmers are getting into this without a lot of background knowledge and making heavy use of Adafruit libraries (which are typically contained within classes) while probably having no idea what the difference between heap and stack memory is.

Personally I like the organisation of classes and would definitely fit into the category of liking things well presented. However I’m wondering if the complexities of class and object use (especially in embedded environments) outweigh the potential benefits, at least for someone with limited C++ experience. Or then again maybe I’m just over thinking things!

Having said this, do you have an answer for the last past of my question above? As in how to have access to an objects members from multiple .cpp files?

I think @bko was rather talking for the general case and not for one object which will exist the whole lifetime of your application.
For example the StringClass is one such class that may cause heap fragmentation if not used wisely.
For some String objects it is better to be instantiated once and have its maximum extent reserved once for reuse rather than have it shrink and grow and getting relocated from time to time.

Similarly for the reason why libraries usually come in classes although they might be only used once (noramlly), what if there is a "bonkers" user who wants to have e.g. two, three, ten displays on his one device? Packaging this into a class makes things just that much easier.

Next, is function/field names. Imagine a library bringing its own int i; or void run(). Sure you could use namespaces for your "flat" functions/fields to keep them seperate, but why not just go the whole way?


I don't quite follow here

Why would you need multiple constructors at all?
You can have multiple constructors in a class, but these are only part of the class - why would they be scattered over multiple files in order to access an object? :confused:

To get access to an object you would do with most other variables.
You can either pass an object pointer or a reference to that object.

Thanks @ScruffR

Good points, As for my last comment that you didn’t follow, to rephrase, I’m trying to understand how best to have access to an object from multiple files. Say for my LEDControl example above, imagine you want to have control over the same LEDControl object from two or more files. How should each file access it? Should the object be instantiated/constructed in one file only? I assume the object shouldn’t be created twice (if there’s just one LED)?

To give a code example:

main.cpp

#include "LEDControl.h"

LEDControl led;  //Creating object led of type LEDControl

void setup(){
}

void loop(){
   led.switchOn();
   delay(1000);
   led.switchOff();
   delay(1000;
}

Suppose we also want to have access to the same led object in another file, say peripherals.cpp, how should peripherals.cpp access that object?

Sorry I feel that there’s probably a fairly basic answer for this but the thread has become a bit protracted as I’ve asked a few different questions at the same time, however lot’s of interesting points have been made so it’s all good.

You are asking great questions. You can use the extern keyword to allow access to an object across different source files:

Check out this link to Stack Overflow explanation/example.

Googling extern with C++ will get you some more examples.

1 Like

OK, I see what you are asking now. Your question in OO terms is, "What if object A needs to use some part of object B's interface?" for which there are many answers:

  • If object A needs to just use the public interface of B, then A should probably take a reference to B as an argument for those methods or hold a reference given to it in a "begin" method. You mentioned singleton pattern earlier, try googling for "facade pattern" and "adapter pattern". This mostly comes up when you have existing code (like Arduino objects) that you cannot refactor.

  • But in new code that kind of close coupling sometimes means that you have not thought through the interface as well as you could have or you cannot change an existing interface.

  • In C++ we also have friend classes which are classes that are so related that they need special access to internals of their friends that are not public. This can get overused and should be limited to special circumstances.

  • If the objects are well designed, then it just feels natural: a schematic object has one or more electronic component objects and knows how to ask the components questions like, "What is your PCB footprint?" or "What is your value?" or "What is your wattage rating?". This feels natural since the hierarchy helps the separation of concerns-each object knows only about itself (resistor, capacitor, etc.) but the next level up (schematic) understands how to aggregate the information from its parts. This is usually handled with object containment: the schematic holds references to all its components and completely controls the lifetimes of the component objects. You might also want to google for the "visitor pattern" which is a complicated double-callback scheme but a very powerful way to traverse graphs of objects.

2 Likes

Sorry, I had to leave, but have now added (updated) to my original post.

1 Like

Hello All,

I was just about to ask this in a seperate post but I think it’s directly related to this discussion.

I’ve created a few custom libraries for some peripheral devices I have attached to the particle.
I’ve been using the libraries by including them in the main program as an object decleration but I’d like to set them up in the same manner that the particle firmware uses it’s classes. So that you can use the same class throughout many other classes.

One example I have of this functionality is the particle firmware design. Is my understanding of the concept correct?

Looking at the Serial class it’s included using a #defined

extern USBSerial& _fetch_usbserial();
#define Serial _fetch_usbserial()

So when ever the header is included you have access via the definition method.

Then in the method it returns a static object reference

USBSerial& _fetch_usbserial1()
{
  HAL_USB_USART_Config conf = acquireUSBSerial1Buffer();
  static USBSerial _usbserial1(HAL_USB_USART_SERIAL1, conf);
  return _usbserial1;
}

So is this effectively a Singleton Pattern? but rather than call a .instance() that is tidied up by a #define.

Like an LED I’m attaching an Accelerometer to the particle. Does it then make sense to create all custom peripherals using this method?, to stick with the particle convention.

Thankyou