/* Lecture code 16.1
 *
 * Creative uses of inheritance: Disallowing copying, counting classes, creating singletons.
 */

#include <iostream>
#include <memory> // for auto_ptr
using namespace std;

/* Base class that makes an object uncopyable.  Classes should inherit
 * privately from Uncopyable.
 */
class Uncopyable
{
	/* In lecture we left Uncopyable's default constructor in the public section.
	 * It really should be protected, though, so that you cannot create instances
	 * of Uncopyable.
	 */
protected:
	Uncopyable() {}
private:
	Uncopyable(const Uncopyable &other);
	Uncopyable& operator =(const Uncopyable &other);
};

/* A class that uses the Curiously Recurring Template Pattern to allow multiple
 * classes to each have a counter tracking the number of active instances.  The
 * template parameter here should be instantiated with the type of the base 
 * class.
 */
template<typename T> class Counter
{
public:
	Counter() { ++numInstances; }
	~Counter() { --numInstances; }
	
	/* Note: Should probably add copy constructor here in case derived class
	 * is copied.
	 */

	static int getNumInstances() { return numInstances; }
private:
	static int numInstances;
};

template<typename T> int Counter<T>::numInstances = 0;

/* A class that is uncopyable and counted. */
class CountMe: private Uncopyable, public Counter<CountMe>
{

};

/* A class that is uncopyable and counted. */
class CountMeToo: private Uncopyable, public Counter<CountMeToo>
{
};


/* A base class that can be used to make a class a Singleton.  Using the
 * CRTP, this class is able to export member functions that normally the base
 * class would have to define.
 */
template <typename T>
class Singleton: private Uncopyable
{
public:
	static T* getInstance()
	{
		if(instance.get() != NULL)
			return instance.get();

		instance.reset(new T);
		return instance.get();
	}
protected:
	Singleton() {}
	~Singleton() {}

private:
	static auto_ptr<T> instance;
};

template <typename T> auto_ptr<T> Singleton<T>::instance;

/* Demonstrating use of Singleton.  Note that we've made Singleton a friend
 * and that we've made the constructor private.
 */
class ThisIsASingleton: public Singleton<ThisIsASingleton>
{
private:
	friend class Singleton<ThisIsASingleton>;
	ThisIsASingleton() {}
}