Developing A Once-Only Initialised Class

Environment: Visual C++ Version 6

Often, we need a once-only initialised class that is global to the entire system. Examples of such a class would be the loading of a library, or options from the Registry.

This is a base class which provides (a) an initialisation, only if the class is used and (b) ensures a once-only instance for the application.

template <class CLASS>
class CStaticClass
{
public:
  virtual ~CStaticClass() { };

  static CLASS &Get()
  {
    static CLASS m_theObject;

    m_theObject.Initialise();
    return m_theObject;
  }

  void Initialise()
  {
    if (!m_fInitialised)
    {
      OnInitialise();
      m_fInitialised = TRUE;
    }
  }
  
protected:
  CStaticClass()
  {
    m_fInitialised = FALSE;
  }

  virtual void OnInitialise() = 0;

private:
  BOOL m_fInitialised;
} ;

An example of use would be for loading a library:

class CMyLibrary : public CStaticClass<CMyLibrary>
{
public:
  CMyLibrary()
  {
    m_hLibrary = NULL;
    m_pfnFunction = NULL;
  }


  virtual ~CMyLibrary()
  {
    if (m_hLibrary != NULL)
    {
      ::FreeLibrary(m_hLibrary);
    }
  }

  void DoFunction()
  {
    if (m_pfnFunction != NULL)
    {
      m_pfnFunction();
    }
    else
    {
      ASSERT(FALSE);
    }
  }

protected:
  virtual void OnInitialise()
  {
    m_hLibrary = ::LoadLibrary("mylibrary.dll");

    if (m_hLibrary != NULL)
    {
      m_pfnFunction = ::GetProcAddress(m_hLibrary, "MyProc");
    }
  }

private:
  HMODULE m_hLibrary;
  FARPROC m_pfnFunction;
} ;

So, to call the designated function, use this line of code:

  CMyLibrary::Get().DoFunction();


About the Author

David McClarnon

He first encountered Windows programming using Visual C++/MFC version 1.5 on Windows 3.11 a very long time ago. He is now a contract developer specialising in .NET/native interop with p/invoke.

Comments

  • A.k.a singleton pattern

    Posted by Legacy on 12/04/2002 12:00am

    Originally posted by: Per

    Looks pretty much like a template version of the singleton
    
    design pattern, which is commonly used for ensuring only one instance of a class.

    If you haven't heard of "design patterns" in a programming
    context, search the web for info _now_ :-)


    Example of a typical singleton:

    // MyClass is a singleton and there can thus exist at most
    // 1 instance of it which it basically ensures all by itself.

    MyClass
    {
    public:

    void Bar()
    {
    cout << "Boo!";
    }

    static MyClass* getInstance()
    {
    if (sInstance==0)
    {
    sInstance = new CMyClass()
    }

    return sInstance;
    }

    static void destroyInstance()
    {
    delete sInstance;
    sInstance = 0;
    }

    private:
    // Private constructor to get compile error
    // on "new MyClass" outside the class' scope.
    MyClass() {}
    virtual ~MyClass() {}

    // Copy constructor deliberately not implemented
    explicit MyClass(const MyClass&);

    // Assignment operator deliberately not implemented
    MyClass& operator = (const MyClass&);

    static MyClass* sInstance;
    }; // MyCLass

    // in the .cpp initialize sInstance
    MyClass* MyClass::sInstance = 0;
    .
    .
    .

    // So to use it:
    void SomeFunc()
    {
    MyClass* foo = MyClass::getInstance();

    foo->Bar();

    .
    .
    .

    Reply
  • This doesn't work at all, sloppy idea.

    Posted by Legacy on 12/04/2002 12:00am

    Originally posted by: Pass over

    Try the following testing program, you will see that your method doesn't work at all, you have a totally wrong idea of control singleton:

    void main()
    {
    printf("size = %d\n", sizeof(CMyLibrary));
    CMyLibrary lib1, lib2, lib3;
    printf("address: lib1 = %d, lib2 = %d, lib3 = %d\n", &lib1, &lib2, &lib3);
    printf("address2: lib1 = %d, lib2 = %d, lib3 = %d\n",
    &lib1.Get(), &lib2.Get(), &lib3.Get());
    }

    Reply
  • The drawbacks

    Posted by Legacy on 12/04/2002 12:00am

    Originally posted by: Darwen

    I should have added the drawbacks of this method -

    To make it work you have to either

    (a) have the constructor of the inherited classes as public

    or

    (b) declare CStaticClass as a friend of the inherited class

    For (b) e.g. -

    class CMyInheritedClass
    : public CStaticClass<CMyInheritedClass>
    {
    public:
    virtual ~CMyInheritedClass()

    private:
    CMyInheritedClass();

    friend CStaticClass<CMyInheritedClass>;
    };

    If you use (a) then people can create more than one instance of the class, if you use (b) they can't.

    Darwen.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds