0

Sorry if this seems to be a beginner question, but I can't seem to work out the best approach for my C++ library. I have build a static library, which contains driver API handling code. Currently in order to use it in a higher layer of the software (a simple app with GUI), I need to link the library to the project and create a new instance of a class which exists in this library to access all of its public methods. When a new instance of this class is created, all necessary objects required by the code to work are initialized. I would like to skip the instantiation step and enable the potential users to have it working only by including the library in their code. To picture this better, here's a code example:

What I currently have:

#include "myLibrary.h"

// Some GUI code here

MyLibrary *mLib;
mLib = new MyLibrary;

// Using the library methods
mLib->startProcess();

What I would like to have:

#include "myLibrary.h"

MyLibrary::startProcess();

I am working in Qt Creator, but don't mind migrating to a different IDE (Visual Studio would also be fine). The files I have in this projects are:

  • MyLibrary.h (declarations)
  • MyLibrary_global.h (an include list and export settings created by Qt Creator)
  • MyLibrary.cpp (implementation)

Any help would be appreciated. In case further clarification on my issue is needed, I will edit this question to make it clear.

EDIT: After digging in the driver API documentation, I have found out, that the way it is implemented will require me to create an instance of the MyLibrary class. I have gotten plenty knowledge from the comments below and marked the singleton-response as valid, since that would be the way for me to proceed if it was possible.

szumial
  • 63
  • 7
  • 6
    Do your text-book, tutorial or class mention *static* member functions? – Some programmer dude Jan 18 '21 at 11:57
  • 7
    Not related, but using a pointer and `new` in this scenario seems to serve no purpose. Just do `MyLibrary myLib; myLib.startProcess();`. – super Jan 18 '21 at 11:59
  • Is there a reason to have a class in the first place? – NotAProgrammer Jan 18 '21 at 12:02
  • Hm... isn't that just namespace syntax in your dream scenario? – Alexander Mayer Jan 18 '21 at 12:03
  • 1
    @AlexanderMayer The "problem" with a `namespace` is that anyone could add members to them. – Some programmer dude Jan 18 '21 at 12:05
  • @Someprogrammerdude Fair point. Thanks for pointing out the issue - it may be very undesirable to have that behavior. – Alexander Mayer Jan 18 '21 at 12:11
  • A general reply to comments above: - I have not tried with static member functions extensively - does that mean all of the accessible ones would need to be static? - I guess the pointer could be removed - Yes, I will need several classes in the library as it grows (which itself is a design issue I have - offtopic) - I was also thinking wrapping the implementation in a common namespace would make sense, however, I still couldn't handle the instantiation problem – szumial Jan 18 '21 at 12:12

1 Answers1

2

Supposed you have this:

#include "myLibrary.h"

// Some GUI code here

MyLibrary *mLib;
mLib = new MyLibrary;

// Using the library methods
mLib->startProcess();

Your library can hide the MyLibrary object like this:

startProcess() {
    static MyLibrary* myLib = new MyLibrary;
    myLib->startProcess();
}

Such that the user code looks like this:

#include "myLibrary.h"

MyLibrary::startProcess();

The function local static myLib will be initialized on first call of the method.

However, you probably want to use the MyLib instance also from other places in your code and wrapping it inside startProcess is not really an option. You'd rather use the much frowned upon Singleton Pattern. Here is a Q&A abuot the Meyers Singleton: Is Meyers' implementation of the Singleton pattern thread safe?.

I am not going into details, because the Singleton Pattern is well documented across the web. Only to outline the rough idea, this would allow you to get the desired user code (not tested):

struct MyLibrary {
     static void startProcess() {
         instance().doStartProcess();
     }
     private:

     MyLibrary() = default;          // private constructor
     MyLibrary(MyLibrary&) = delete; // no copies
     static MyLibrary& instance() {
          static MyLibrary myLib;              // the actual instance
          return myLib;
     }
     void doStartProcess(){
          // actual implementation
     }
}

Note that the actual instance myLib is lazily initialized, ie only the first time instance() is called the function local static myLib is initialized.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • I will likely need one instance of MyLib in the main application - most importantly this has to initialize a driver connection and adjust some parameters of a device I am working with. Don't know if that's good practice, but perhaps I could initialize the first call in the Main (or Qt's MainWindow) of the GUI app? – szumial Jan 18 '21 at 12:20
  • @szumial read about the Singleton Pattern, that will answer your questions. Don't get confused by the crusade of complaints against the pattern. It can be misused and it can be used. – 463035818_is_not_an_ai Jan 18 '21 at 12:22
  • I have used it in another project for handling a database connection. Although I have seen multiple threads on the Internet warning against it. – szumial Jan 18 '21 at 12:50
  • @szumial its a pattern that is easy to critize, because of its close relation to globals (a singleton is a global in disguise with the known downsides) and because the focus on "only a single instance", but the latter is to a large part just complaining that a hammer is the wrong tool for a screw – 463035818_is_not_an_ai Jan 18 '21 at 13:09
  • how about accessing other methods in the library then? would I need to make them all static? – szumial Jan 18 '21 at 13:24
  • @szumial you need not make any of them `static`. Only `instance` needs to be static. The only reason I made `startProcess` static was to have the exact user code you were asking for. They could also call `MyLibrary::instance().any_non_static_method()` – 463035818_is_not_an_ai Jan 18 '21 at 13:28
  • `static myLib;` --> `static MyLibrary myLib;`? – JHBonarius Jan 22 '21 at 12:16
  • @JHBonarius thanks. Actually I remember that I was staring at it for a minute while writing, thinking that it doesn't look right, but I didn't get it. Guess thats what happens when posting untested code ;) – 463035818_is_not_an_ai Jan 22 '21 at 12:57