How would I write a C++ class of which only one can be created ever be instantiated in any program.

I know that

ClassName* objectName = new ClassName();

instantiates an object, but how would I make it so when you try to instantiate it more than once you still end up with a reference to the first instance?

Even if you could point me to a reference where I can read how this might be done I would greatly appreciate it.

Recommended Answers

All 6 Replies

This is called a Singleton class.

The most straight-forward way to implement it in C++ is as follows:

// in the header file:

class MySingleton {
  private:
    // private constructor:
    MySingleton() { };

    // private copy-constructor (left undefined):
    MySingleton(const MySingleton&);
    // private copy-assignment operator (left undefined):
    MySingleton& operator=(const MySingleton&);

  public:

    // public static function returning a reference to the singleton class:
    static MySingleton& getInstance();

};

// in the cpp file:

MySingleton& MySingleton::getInstance() {
  static MySingleton instance;   // a static local variable is initialized on first call to the 
                                 // function only, afterwards, it is always the same variable
                                 // for every subsequent calls to the function.
  return instance;
};

You can, of course, do the same but return a pointer, whichever you prefer.

With the above scheme, the user of the class simply has to use the getInstance() static member function to obtain the unique instance of the class. The instance will be unique within a single program. Because the copy-constructor and copy-assignment operators are private and undefined, it is impossible for a user to copy the instance either (called the Noncopyable idiom).

OK. I found a singleton code and modified it for my assignment. Here is my code...

// Rectangle.h

#ifndef RECTANGLE_H_INCLUDED
#define RECTANGLE_H_INCLUDED

class Rectangle
{
public:
    /** Checks if this is the first instance of a Rectangle and either creates or returns a pointer to the first instance of the object
     *
     * \param l int the length of the rectangle
     * \param w int the width of the rectangle
     * \return Rectangle* a pointer to the first instance of a Rectangle object
     *
     */
    static Rectangle* getInstance(int l, int w);

    /** Returns the area of the rectangle
     *
     * \return int the area of the rectangle
     *
     */
    int getArea() const;

    /** The default destructor
     */
    ~Rectangle();

private:
    /** The default constructor
     */
    Rectangle();

    /** A constructor for a Rectangle object with length and width parameters
     *
     * \param l int the length of the rectangle
     * \param w int the width of the rectangle
     *
     */
    Rectangle(int l, int w);

    /**< Static indicator set to true if a previous instance of a Rectangle object has been created */
    static bool instanceFlag;

    /**< A static pointer to a the first instance of a Rectangle object */
    static Rectangle* firstInstance;

    /**< The length of the Rectangle */
    int length;

    /**< The width of the Rectangle */
    int width;
};


#endif // RECTANGLE_H_INCLUDED

Next file

// Rectangle.cpp

#include "rectangle.h"

#include <cstddef>

/** Checks if this is the first instance of a Rectangle and either creates or returns a pointer to the first instance of the object
 *
 * \param l int the length of the rectangle
 * \param w int the width of the rectangle
 * \return Rectangle* a pointer to the first instance of a Rectangle object
 *
 */
Rectangle* Rectangle::getInstance(int l, int w)
{
    /**< If there are no prior instances of the object, create a new object and return a pointer to it */
    if(! instanceFlag)
    {
        /**< Create a new Rectangle object on the heap and assign it to the first instance pointer */
        firstInstance = new Rectangle(l, w);

        /**< Set the instance flag to true */
        instanceFlag = true;

        /**< Return the pointer to the first instance of the Rectangle object */
        return firstInstance;
    }

    /**< Else return the pointer to the first instance of the object */
    else
    {
        return firstInstance;
    }
}

/** Returns the area of the rectangle
 *
 * \return int the area of the rectangle
 *
 */
int Rectangle::getArea() const
{
    /**< Return the area of the rectangle */
    return length * width;
}

/** The default destructor
 */
Rectangle::~Rectangle()
{
    /**< Set the instance flag to false */
    instanceFlag = false;

    /**< Return the memory used by the rectangle object to the heap */
    delete firstInstance;
}

/** The default constructor
 */
Rectangle::Rectangle()
{
    /**< Set the length and width of the rectangle to 0 */
    length = 0;
    width = 0;
}

/** A constructor for a Rectangle object with length and width parameters
 *
 * \param l int the length of the rectangle
 * \param w int the width of the rectangle
 *
 */
Rectangle::Rectangle(int l, int w)
{
    length = l;
    width = w;
}

/** Set the state of the static instance flag to false
 */
bool Rectangle::instanceFlag = false;

/** Set the static first instance pointer to NULL
 */
Rectangle* Rectangle::firstInstance = NULL;

Next file

// main.cpp

/** Frank Jamison
 *
 * CSC 300 Homework Assignment
 * Assignment 1
 *
 */

     /** Instructions
      *
      * Using visual studio for C++, write a C++ class of which only one can be created ever be instantiated in any program.
      * Write a demonstrating driver program with a main to illustrate how when you try to instantiate it more than once
      * you still end up with a references to the first instance.
      * Document your C++ class header and implementation files explaining the purpose and reason of each element
      * and how it causes only ever one instance to be instantiated.
      *
      */

#include <iostream>

using namespace std;

#include "rectangle.h"

int main()
{
    /**< Create two pointers to Rectangle objects */
    Rectangle *a1,*a2;

    /**< Initialize the first pointer by calling the Rectangle function getInstance with length and width parameters of 3 and 3 */
    a1 = Rectangle::getInstance(3, 3);

    /**< Get the area of the first instance of the Rectangle object */
    int area1 = a1->getArea();

    /**< Initialize the second pointer by calling the Rectangle getInstance function with length and width parameters of 5 and 5 */
    a2 = Rectangle::getInstance(5, 5);

    /**< Get the area of the second instance, which is actually the area of the first instance since only one instance can be created */
    int area2 = a2->getArea();

    /**< Display the area of the first instance of the Rectangle object */
    cout << "The area of the first instance is " << area1 << "\n";

    /**< Display that the getArea function called on the second Rectangle is actually the area of the first Rectangle object */
    cout << "The area of the second instance is " << area2 << "\n";

    return 0;
}

One thing I don't understand though...

Why is it
a1 = Rectangle::getInstance(3, 3);
Instead of
a1 = Rectangle.getInstance(3, 3);
on line 32 of the main.cpp file when calling the getInstance function?

The Rectangle::getInstance(3, 3); is the syntax for calling a static member function of a class. Because a static member function is associated to the class only, not to objects of the class. In other words, regular member functions operate on one instance of the class (object), but static member functions do not, they are just defined as part of the class. Here are the different syntaxes:

MyClass my_object;  // this declares an object of class 'MyClass'.

my_object.callRegularMemberFunction();  // calls the function on the object 'my_object'.

MyClass::callStaticMemberFunction();  // calls a static function belonging to 'MyClass'.

my_object.callStaticMemberFunction();  // this is just for convenience, you can also call a static 
                                       // function on a object, but it is no different from the 
                                       // previous syntax with 'MyClass::'.

MyClass* my_object_ptr = new MyClass;  // declares a pointer to an object of class 'MyClass' and 
                                       // initializes it to point to a dynamically allocate object.

my_object_ptr->callRegularMemberFunction();  // calls the function on object pointed to by pointer.

my_object->callStaticMemberFunction();  // same as above, just an alternative syntax for calling 
                                        // the static function.

As for the Singleton implementation that you chose to use, it is a terrible one. There are many reasons why I recommended the Singleton implementation that I posted earlier. There are many alternatives that are really bad, the one you chose isn't the worse I've seen, but definitely not great. I highly recommend you go with the implementation I suggested instead.

As so:

Rectangle.h

#ifndef RECTANGLE_H_INCLUDED
#define RECTANGLE_H_INCLUDED

class Rectangle
{
public:
    /** Checks if this is the first instance of a Rectangle and either creates or returns a pointer to the first instance of the object
     *
     * \param l int the length of the rectangle
     * \param w int the width of the rectangle
     * \return Rectangle* a pointer to the first instance of a Rectangle object
     *
     */
    static Rectangle* getInstance(int l, int w);

    /** Returns the area of the rectangle
     *
     * \return int the area of the rectangle
     *
     */
    int getArea() const;

    /** The default destructor
     */
    ~Rectangle();

private:
    /** A constructor for a Rectangle object with length and width parameters
     *
     * \param l int the length of the rectangle
     * \param w int the width of the rectangle
     *
     */
    Rectangle(int l, int w);


    // NOTE: You need to have a private and undefined copy-constructor and copy-assignment op.:
    Rectangle(const Rectangle&);
    Rectangle& operator=(const Rectangle&);


    /**< The length of the Rectangle */
    int length;

    /**< The width of the Rectangle */
    int width;
};


#endif // RECTANGLE_H_INCLUDED

Rectangle.cpp

#include "Rectangle.h"

#include <cstddef>

Rectangle* Rectangle::getInstance(int l, int w)
{
    static Rectangle firstInstance(l, w);
    return &firstInstance;
}

int Rectangle::getArea() const
{
    return length * width;
}

Rectangle::~Rectangle() { }

Rectangle::Rectangle(int l, int w)
{
    length = l;
    width = w;
}

The main.cpp file remains the same.

That code isn't working with my code.

Can you check it?

Edit: Now it's working.

Question: The getInstance function call is Rectangle* Rectangle::getInstance(int l, int w) but it's returning a reference instead of a pointer. How does that work?

In the code above, it does return a pointer. This returns a pointer:

Rectangle* Rectangle::getInstance(int l, int w)
{
    static Rectangle firstInstance(l, w);
    return &firstInstance;
};

If you want to return a reference, you can use this:

Rectangle& Rectangle::getInstance(int l, int w)
{
    static Rectangle firstInstance(l, w);
    return firstInstance;
};

Either way, it's pretty much equivalent. A pointer is just a bit easier to deal with, but a reference is often preferred as a matter of good coding style.

One of the main reasons to use references rather than pointers is that you don't need to check for a null pointer. The object must exist to get a reference to it. A pointer may or may not point to a real object (null if not).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.