2

For a c++ application which I'm currently being busy to develop, I have several classes which I need to access through my entire code, without creating a new object

So searching I have found that one of methods that can be used is with the extern linkage specifier.

I would like to know what is best way to use this extern method, I wrote a little sample code

classone.h
#ifndef CLASSONE_H
#define CLASSONE_H

class ClassOne
{
public:
    ClassOne();

    void showClassOneInt();

private:
    int m_classOneInt;
};

extern ClassOne *classOne;
---------------------------------------
classone.cpp
#include "classone.h"

#include <QDebug>

ClassOne *classOne;

ClassOne::ClassOne()
{
    m_classOneInt = 1;
}

void ClassOne::showClassOneInt()
{
    qDebug() << "ClassOneInt: " << m_classOneInt;
}
---------------------------------------
classtwo.h
#ifndef CLASSTWO_H
#define CLASSTWO_H

class ClassTwo
{
public:
    ClassTwo();

    void showClassTwoInt();

private:
    int m_classTwoInt;
};

#endif // CLASSTWO_H
---------------------------------------
classtwo.cpp
#include "classtwo.h"

#include <QDebug>

ClassTwo::ClassTwo()
{
    m_classTwoInt = 2;
}

void ClassTwo::showClassTwoInt()
{
    qDebug() << "ClassTwoInt: " << m_classTwoInt;
}
---------------------------------------
classthree.h
#ifndef CLASSTHREE_H
#define CLASSTHREE_H

class ClassThree
{
public:
    ClassThree();

    void showClassThreeInt();

private:
    int m_classThreeInt;
};

#endif // CLASSTHREE_H
---------------------------------------
classthree.cpp
#include "classthree.h"

#include <QDebug>

ClassThree::ClassThree()
{
    m_classThreeInt = 3;
}

void ClassThree::showClassThreeInt()
{
    qDebug() << "ClassThreeInit: " << m_classThreeInt;
}
---------------------------------------
classtest.cpp
#include "classtest.h"
#include "classone.h"
#include "classtwo.h"
#include "classthree.h"

//Class one pointer already in header

//Class two
extern ClassTwo *classTwo;

//Class three
extern ClassThree *classThree;

ClassTest::ClassTest()
{
    //Execute class one
    classOne->showClassOneInt();

    //Execute class two
    classTwo->showClassTwoInt();

    //Execute class three
    classThree->showClassThreeInt();
}
---------------------------------------
main.cpp
#include <QCoreApplication>
#include "classone.h"
#include "classtwo.h"
#include "classthree.h"
#include "classtest.h"

//Class one pointer already in header file

//Class two pointer
ClassTwo *classTwo;

//Class three pointer
ClassThree *classThree;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //Create object for class one
    classOne = new ClassOne;

    //Create object for class two
    classTwo = new ClassTwo;

    //Create object for class three
    ClassThree three;
    classThree = &three;

    //Create a classTest object
    ClassTest test;

    return a.exec();
}

Please could you tell me what is the best way, thanks for you help.

pjwl
  • 21
  • 3

2 Answers2

2

The best way is to not do it and instead use dependency injection.

If you choose to do it anyway, you should at least use getter/factory functions (i.e. ClassOne &getClassOne())) so you can:

  • be sure random code can't change the objects and
  • handle order of construction implicitly by constructing on first use (sometimes appropriate, sometimes not).
Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • 1
    So something like: `ClassTest::ClassTest(classOne& classOne, ClassTwo& classTwo, ClassThree& classThree)`. – Jarod42 Apr 26 '17 at 14:22
  • The problem is that I need to acces for example a serialport through the entire application, but in some classes this will no be the case that I need the serialport. – pjwl May 01 '17 at 11:45
  • @user3458964, why is that a problem? You should have a class responsible for handling the serial port, which you construct in `main` and pass to those parts of the application that need access to it. Or you can make it available from your class derived from `QApplication`, that is a singleton already anyway. – Jan Hudec May 01 '17 at 16:00
2

Having a global state is generally not a great idea, seek to eliminate it.

If that cannot be done, try the singleton pattern.

class Singleton
{
    Singleton();  //keep constructors private to avoid creation by others
    static Singleton inst;
public:
    static Singleton& Instance() {return inst;}
};
Singleton Singleton::inst;
Passer By
  • 19,325
  • 6
  • 49
  • 96
  • shouldn't `Instance()` be static too? And do you really want to return a non-const reference? – Walter Apr 26 '17 at 14:32
  • lol of course it should be `static`. I'm dumb. The `const`ness is dependent on what the class does, so I wouldn't necessarily just plop that in. – Passer By Apr 26 '17 at 14:35
  • Thanks.. I need a global class for the use of serial port, which is needed trough the entire code. I have heared thats singleton not always are the best choice.? – pjwl Apr 27 '17 at 09:02
  • Singleton is an *anti*-pattern: it mixes the availability of a well known instance into the logic of the class itself. It is better to put the well known instance in some kind of “context” object, separate from the class itself. That way you can replace the instance in the context with a mock for testing or when it turns out you actually need to extend it in some cases. – Jan Hudec May 01 '17 at 15:46
  • Also, Singleton is a Java pattern. It exists in large part because Java can't have functions outside classes, so it puts the `getInstance()` into the class it returns. But this is a C++ question and in C++ functions can be outside of classes, which is more appropriate here: have `getClassA()`, not `ClassA::getInstance()`. – Jan Hudec May 01 '17 at 15:51
  • @JanHudec I agree mostly with your first point with some caveats, it doesn't actually matter since we ruled out dependency injection, but I strongly disagree with `getClassA()`. `getInstance()` is essentially a "constructor" of sorts, having it outside the class makes little to no sense, made worse if it actually needed to be friended for lazy initialization. And no I'm not endorsing lazy singletons. – Passer By May 01 '17 at 16:19
  • @PasserBy, the thing is that the existence of well known instance is (usually) *not* a property of the class itself. It is the application that needs a shared instance, so it should be the application (the function/class implementing start-up) that should create it and put it somewhere public, e.g. in some “context”. See also [Singletons: Solving problems you didn’t know you never had since 1995](http://www.onelib.org/article/singletons-solving-problems-you-didnt-know-you-never-had-since-1995). – Jan Hudec May 01 '17 at 16:38
  • @JanHudec Point taken – Passer By May 01 '17 at 17:29