V
velthuijsen
I've been reading (and using the examples in) Thinking in C++ (vol 2).
One of the things that the author shows you can do with templates is
the following:
#include <iostream>
using namespace std;
template<class T>
class Counted
{
static int count;
public:
Counted() { ++count; }
Counted(const Counted<T>&) { ++count; }
~Counted() { --count; }
static int getCount() { return count; }
};
template<class T>
int Counted<T>::count = 0;
// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};
int main()
{
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
CountedClass2 c;
cout << CountedClass2::getCount() << endl; // 1 (!)
} ///:~
I've tried adapting this idea to the following class that I've
used/created to try out some other things (Below is the almost working
example).
Header file:
One of the things that the author shows you can do with templates is
the following:
#include <iostream>
using namespace std;
template<class T>
class Counted
{
static int count;
public:
Counted() { ++count; }
Counted(const Counted<T>&) { ++count; }
~Counted() { --count; }
static int getCount() { return count; }
};
template<class T>
int Counted<T>::count = 0;
// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};
int main()
{
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
CountedClass2 c;
cout << CountedClass2::getCount() << endl; // 1 (!)
} ///:~
I've tried adapting this idea to the following class that I've
used/created to try out some other things (Below is the almost working
example).
Header file:
Code:
#ifndef ID_CLASS_H
#define ID_CLASS_H
#include <map>
// magic number defines
#define NOT_A_VALID_ID -1
template<class T>
class ID_Class
{
private:
static std::map<int, int> ID_Map;
int ID_Value;
void DecrementReference();
void IncrementReference();
public:
// Only reason to ever NOT use the default constructor is when you
read
// the IDs from a source instead of creating new IDs.
ID_Class(int tID);
ID_Class();
~ID_Class();
ID_Class(const ID_Class<T>& Right);
ID_Class<T>& operator= (const ID_Class<T>& Right);
int Get_ID() const;
// Test/debug functions below this comment
void DumpMap() const;
};
#endif
cpp:
#include "ID_Class.h"
#include <stdexcept>
#include <ostream>
// note that #include <map> has been defined in the header. This is
needed
// for the static definition used there.
using std::cout;
using std::overflow_error;
using std::bad_alloc;
using std::pair;
using std::map;
template<class T>
map<int, int> ID_Class<T>::ID_Map;
// private functions
template<class T>
void ID_Class<T>::DecrementReference()
{
map<int,int>::iterator it = ID_Map.find(ID_Value);
--(it->second);
if ( it->second < 1)
{
ID_Map.erase(it);
}
}
template<class T>
void ID_Class<T>::IncrementReference()
{
map<int,int>::iterator it = ID_Map.find(ID_Value);
++(it->second);
if (it->second < 1)
{
throw overflow_error("To many copies exist");
}
}
// public functions
template<class T>
ID_Class<T>::ID_Class(int tID)
{
ID_Value = tID;
if ((ID_Map.insert(pair<int,int>(ID_Value,1))).second == false)
{
throw bad_alloc();
}
}
template<class T>
ID_Class<T>::ID_Class()
{
ID_Value = 1;
map<int,int>::const_iterator it (ID_Map.begin());
map<int,int>::const_iterator itEnd (ID_Map.end());
while(( it != itEnd) && (ID_Value == (*it).first))
{
++ID_Value;
++it;
}
if (ID_Value < 1)
{
throw overflow_error("Requested negative ID");
}
if ((ID_Map.insert(pair<int,int>(ID_Value,1))).second == false)
{
throw bad_alloc();
}
}
template<class T>
ID_Class<T>::~ID_Class()
{
DecrementReference();
}
template<class T>
ID_Class<T>::ID_Class(const ID_Class<T>& Right)
{
ID_Value = Right.ID_Value;
IncrementReference();
}
template<class T>
ID_Class<T>& ID_Class<T>::operator= (const ID_Class<T>& Right)
{
DecrementReference();
ID_Value = Right.ID_Value;
IncrementReference();
return *this;
}
template<class T>
int ID_Class<T>::Get_ID() const
{
return ID_Value;
}
// Test/Debug functions below this comment
template<class T>
void ID_Class<T>::DumpMap() const
{
map<int,int>::const_iterator it (ID_Map.begin());
map<int,int>::const_iterator itEnd (ID_Map.end());
while (it != itEnd)
{
cout << "ID " << (*it).first << " Has " << (*it).second << " copies"
<< endl;
++it;
}
}
main.cpp:
#include "ID_Class.h"
#include <iostream>
using namespace std
class MainID : public ID_Class<MainID>
{
};
int main( int argc, char* argv[])
{
// MainID TestID;
char t;
cin.get(t);
return(0);
};
I know that I'm missing something here since the code will compile
without a warning but when I uncomment // Main TestID; I get
unresolved externals (ctor & dtor). The question is what is is that am
I missing? What rules am I trying to break? And is there a way around
the problem?