C++ abstract class template - c++

I have the following code:
template <typename T>
class ListBase
{
protected:
int _size;
public:
ListBase() {_size=0;}
virtual ~ListBase() {}
bool isEmpty() {return (_size ==0);}
int getSize() {return _size;}
virtual bool insert(int index, const T &item) = 0;
virtual bool remove(int index) = 0;
virtual bool retrieve(int index, T &item) = 0;
virtual string toString() = 0;
};
My second file defines a subclass:
#define MAXSIZE 50
template <class T>
class ListArray : public ListBase
{//for now to keep things simple use int type only later upgrade to template
private:
T arraydata[MAXSIZE];
public:
bool insert(int index,const T &item)
{
if(index >= MAXSIZE)
return false;//max size reach
if (index<0 || index > getSize() )//index greater than array size?
{
cout<<"Invalid index location to insert"<<endl;
return false;//invalid location
}
for(int i = getSize()-1 ; i >= index;i--)
{//shift to the right
arraydata[i+1]=arraydata[i];
}
arraydata[index] = item;
_size++;
return true;
}
string ListArray::toString()
{
ostringstream ostr;
ostr<<"[";
for(int i = 0; i < _size;i++)
ostr<<arraydata[i]<<' ';
ostr<<"]"<<endl;
return ostr.str();
}
};
My main.cpp:
int main()
{
ListArray<char> myarray;
myarray.insert(0,'g');
myarray.insert(0,'e');
myarray.insert(1,'q');
cout<<myarray.toString();
}
I can't seem to figure out how to use a template with a subclass. When I compile my code, I get the following error:
error C2955: 'ListBase' : use of class template requires template argument list
see reference to class template instantiation 'ListArray' being compiled

You didn't specify the template parameter for ListBase.
template <class T>
class ListArray : public ListBase<T>
---

class ListArray : public ListBase
should be
class ListArray : public ListBase<T>
And you've got a bunch of problems with accessing the base class members. See: Accessing inherited variable from templated parent class.

Related

Problem with conversion from className * to className &(and the reverse)

Can someone , for the love of god please help me. I've been stuck on this for hours
This is the "father" .h file , which i am NOTallowed to alter at all
//------------ Declarations for List traits used in Test1 in main.cpp
template <typename T>
class ListTraits
{
public:
virtual unsigned int size() = 0;
virtual ListTraits& insert(const T& item) = 0;
virtual void print() = 0;
};
//------------ Declarations for List traits used in Test2 in main.cpp
template <typename T>
class ListTraitsExtended
{
public:
virtual const T* getCurrentElement() const = 0;
virtual void advance() = 0;
virtual void rewind() = 0;
};
And this is the "child" .h file ,
#include "ListTraits.h"
#include <array>
template <typename T>
class List : public ListTraits<T>
{
protected:
std::array<int, 7> data;
public:
unsigned int size() override{
return 0;
}
void print() override {
}
List & insert(const T& item) override {
return this;
}
};
Where I always get this error:
'return' cannot convert from List * to List &
If I do
return *this;
I still get errors...
What exactly am I doing wrong?I cant wrap my head around it
List& List::insert(const T &item) is declared to return a reference to List. this is a pointer to List. To return a reference to List, return *this:
List & insert(const T& item) override {
return *this;
}

How to make variable type polymorphism work?

I have a template Node which returns data of type T.
template <class T> Node
{
public:
virtual const T& GetData() = 0;
};
And I want to have derived classes RefNode, and ValueNode that contain Pointers to data, and actual data. So that I can choose whether to work with a copy of data or to work on actual data in a node.
template<class T> class RefNode : public Node<T>
{
public:
RefNode(T *_data) : data(_data) { }
const T& GetData() { return *data; }
protected:
DataType *data;
};
template<class T> class ValueNode : public Node<T>
{
public:
ValueNode(const T&_data) : data(_data) { }
const T& GetData() { return data; }
protected:
T data;
};
I know that templates can't have virtual methods, but I just wanted to illustrate the effect that I wanted to get. The effect that I wanted to get is:
//for class Vector
Vector v, *c;
c = new Vector();
Node<Vector>* node = new RefNode<Vector>(c);
Node<Vector>* node2 = new ValueNode<Vector>(a);
node2->GetData(); //calls ValueNode<Vector>'s GetData();
node->GetData(); //calls RefNode<Vector>'s GetData();
Is there any way in C++ to achieve this kind of behaviour?
EDIT:
I would use GetData() like this:
Vector *vecarr[9];
Node<Vector>* nodes[10];
nodes[0] = new RefNode<Vector>(vecarr[0]);
nodes[1] = new ValueNode<Vector>(Vector(2,3)); //non reference vector
nodes[2] = new RefNode<Vector>(vecarr[1]);
nodes[3] = new RefNode<Vector>(vecarr[2]);
.....
void processPositionNodes(Node<Vector> **nodes, int n)
{
for(int i=0; i< n; i++) //iterate over all nodes
{
Vector vec = nodes[i]->GetData();
//do something with vec
}
}
I want to be able to change the type of data the Node contains, because I want to implement several graph algorithms dealing with different types of data, (Vectors, scalars..)
This code works just fine (there are some minor and unrelevant changes to your version):
#include <iostream>
using namespace std;
template <class T>
class Node
{
public:
virtual const T& GetData() = 0;
};
template<class T>
class RefNode : public Node<T>
{
public:
RefNode(T *_data) : data(_data) { *data = 5; }
const T& GetData() { return *data; }
protected:
T *data;
};
template<class T> class ValueNode : public Node<T>
{
public:
ValueNode(const T&_data) : data(_data) { data = 5; }
const T& GetData() { return data; }
protected:
T data;
};
int main(){
double data;
Node<double>* rn = new RefNode<double>(&data);
Node<double>* rv = new ValueNode<double>(data);
const double& a = rn->GetData();
const double& b = rv->GetData();
cout << a << '\t' << b << endl;
}
However, there are some potential issues with this code: lack of virtual destructor in class Node, lack of copy ctor, dtor, and operator= in class RefNode
As pointed out in the comments, templates can indeed have virtual functions. However this is not going to solve your problem. In fact, you would need those functions to have different return types.
This is a possible template-based solution to your problem, it might not be the most elegant but you (we) can work on this basis
#include <iostream>
using namespace std;
template <typename T, template<typename> class Accessor, template<typename> class Traits>
class Node{
public:
Node() : data(5.){}
typedef typename Traits<T>::type getType;
getType get(){
return static_cast<Accessor<T>*>(this)->implementation();
}
virtual ~Node(){}
protected:
T data;
};
template <typename T>
struct TraitsP{
typedef T* type;
};
template <typename T>
class PointerAccessor : public Node<T, PointerAccessor, TraitsP>{
public:
typename TraitsP<T>::type implementation(){
return &(Node<T, PointerAccessor, TraitsP>::data);
}
};
template <typename T>
struct TraitsD{
typedef T type;
};
template <typename T>
class DirectAccessor : public Node<T, DirectAccessor, TraitsD>{
public:
typename TraitsD<T>::type implementation(){
T ret = Node<T, DirectAccessor, TraitsD>::data;
return ret;
}
};
int main(){
auto np = new PointerAccessor<double>();
double* p = np->get();
cout << *p << endl;
auto np2 = new DirectAccessor<double>();
double d = np2->get();
cout << d << endl;
}
What might seem strange about this solution is PointerAccessor being derived by Node\<..., PointerAccessor, ...>. This is the so called Curiously Recurring Template Pattern (CRTP)

Accessing variables in a template that is a vector of a custom data type with multiple variables

How do I access the variables itemtype and total within the increment function? The code I have below gives me errors as follows
Counter2.h: In member function ‘int Counter::increment(T)’:
Counter2.h:28:31: error: ‘itemtype’ was not declared in this scope
Counter2.h:36:22: error: ‘itemtype’ was not declared in this scope
Counter2.h:36:39: error: ‘total’ was not declared in this scope
I must be able to use the command Counter<T> counter; where T can be any type, such as string and counter.increment()
#include<string>
//#include<cstdlib>
#include<vector>
using std::vector;
using std::string;
template<class T>
class Record{
public:
T itemtype;
int total;
};
template<class T>
class Counter{
vector< Record<T> > data;
public:
int increment(T item);
int count(T item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(T item){
bool check = false;
for(int i=0; i < data.size(itemtype); i++){
if(data[i].itemtype == item){
data[i].total++;
bool check = true;
break;
}
}
if(check == false){
data.push_back(itemtype = item, total = 1);
}
}
int main(){
Counter<string> counter;
counter.increment("orange");
counter.increment("orange");
return 0;
}
In line for(int i=0; i < data.size(itemtype); i++){
will be: for(int i=0; i < data.size(); i++){
And data.push_back(itemtype = item, total = 1); can be:
data.push_back({item, 1}); // by using initializer list ; C++11
or,
Record r;
r.itemtype = item;
r.total = 1;
data.push_back(r);
You can look at : http://www.cplusplus.com/reference/vector/vector/
to know about std::vector.
I'm not too sure I understand what you're after here, though for a start you're trying to access private members of class Record. You could make record a struct (public by default), or provide getters/setters or alternatively add:
friend class Counter;
to Record so that Counter can access its private members.
You can make Record a private structur inside Counter. That will not expose it implementation. You need to change also how you acces data. It is a vector of Record, not a Record. Something like:
template<class T>
class Counter
{
struct Record{ T itemtype; int total; };
vector< Record > data;
public:
int increment(const T& item);
int count(const T& item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(const T& item)
{
auto i=data.begin();
i= find(i,data.end(),[&item](const Record& r)
{return item==r.itemtype;});
if (i!=data.end())
return ++(i->total);
data.push_back({item, 1});
return 1;
}
If you dont like the lambda fun:
template<class T>
int Counter <T> :: increment(const T& item)
{
for(int i=0; i < data.size(); ++i)
if(data[i].itemtype == item)
return ++(data[i].total);
data.push_back({item, 1});
return 1;
}
But i think what you actually need is a multiset (if you dont care about the order). Something like this:
template<class T>
class Counter
{
std::multiset <T> data;
public:
int increment(T item);
int count(T item);
void printSummary();
};
template<class T>
int Counter <T> :: increment(T item)
{
data.insert(item);
return data.count(item);
}

What does "missing template argument" mean?

I'm pretty new to C++ and this site so there are bound to be errors. When I try to compile my code I get errors like error: missing template argument before 'b'. I've been searching the world for answers for hours and it has led me here.
My assignment is to implement a templated class Collection that stores a collection of
Objects using an array, along
with the current size of the collection.
#include <iostream>
#include "collection.h"
using namespace std; v
int main(int argc, char* argv[])
{
collection b; //<----error missing template argument before 'b'
return 0;
}
#ifndef COLLECTION_H
#define COLLECTION_H
#include <iostream>
template <typename obj>
class collection
{
public:
collection();
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
#include "collection.h"
template <typename obj>
collection<obj>::collection() :size(10)
{
col = new obj*[size];
}
template <typename obj>
bool collection<obj>::isEmpty() const
{
for(size_t k = 0; k < size; k++)
{
if(col[k] != NULL)
return false;
}
return true;
}
template <typename obj>
void collection<obj>::makeEmpty()
{
for(size_t k = 0; k < size; k++)
{
col[k] = NULL;
}
}
template <typename obj>
void collection<obj>::insert(obj val)
{
int temp = 0;
for(size_t s = 0; s < size; s++)
{
if(col[s] != NULL)
temp++;
}
if(temp >= size)
{
obj* temp = new obj*[size*2];
for(size_t c = 0; c < size; c++)
temp[c] = col[c];
delete col;
col = temp;
}
else
col[temp] = val;
}
template <typename obj>
void collection<obj>::remove(obj val)
{
for(size_t x = 0; x < size; x++)
{
if (col[x] == val)
{
for(size_t y = x; y < size-1; y++)
{
col[y] = col[y+1];
}
col[size-1] = NULL;
return;
}
}
}
template <typename obj>
bool collection<obj>::contains(obj val) const
{
for(size_t z = 0; z < size; z++)
{
if(col[z] == val)
return true;
}
return false;
}
You have to say what it's a collection of.
template <class A> class collection {}
requires that you use it as
collection<int> b;
or some appropriate type. That then makes a collection of ints. You haven't told it what you want a collection of.
First : Instantiate template by type. So if you have template <typename obj> class T {...}; you should use it like
void main {
T<int> t;
T<bool> t1; // .. etc
}
You can use a template with default value for the typename parameter defined in the class template declaration
template <typename obj = int> class T {/*...*/};
void main {
T<> t;
}
but anyway you should put empty angle brackets when use it without parameter.
Second: While declaring template, place it whole in the header file. Each definition of his methods should be in the file "*.h", don't ask me why, just don't split it to the header and "cpp" file.
Hope it helps.
Well, you're missing a template argument. You can't create a collection object, that's just a template.
You can only create e.g. a collection<int> or collection<std::string>.
You need to specify the type for template, like int or some other type:
collection<int> b;
There are a large number of errors in your code. First define your template in a header file:
In collection.h put the following:
#ifndef COLLECTION_H
#define COLLECTION_H
template <typename obj>
class collection
{
public:
collection() {}
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
Then in a .cpp file inside a main function do the following:
collection<int> b;
Instead of int you can use a different type but the main point is that YOU NEED A TYPE to instantiate a template.

Template Specialization over derived class

I don't know if it is possible, I checked on StackOverflow, I found a lot of stuff but nothing that really fit my problem (or I don't see the relation).
What I'd like to do is something like that:
class Bean
{
public:
Bean(){}
virtual ~Bean(){}
template <class T>
bool set_(T){return false;}
template <class T>
bool get_(T&){return false;}
};
template <class T>
class GenericBean: public Bean
{
protected:
T type;
};
class Prova : public GenericBean<int>
{
public:
Prova(){type = 0;}
template<int> bool set_(int value){ type=value;}
template<int> bool get_(int& value){value = type;}
};
I'd like to have on object like Prova, cast to Bean and get the specialized function,
What I want to do is something like this:
#include <vector>
#include "Bean.h"
using namespace std;
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class ReturnValue, class Item>
bool Get(ReturnValue & val)
{
for(size_t i = 0; i < m_vData.size(); i++)
{
if(m_vData[i].get_<ReturnValue>(val))
return true;
}
}
template <class Item, class Value>
bool Set(Value val)
{
Item bean;
if(bean.set_<Value>(val))
{
m_vData.push_back(bean);
return true;
}
return false;
}
protected:
vector<Bean> m_vData;
};
Main:
#include "VirtualMessage.h"
#include "Bean.h"
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed");
}
this code doesn't compile
Maybe nobody will use it, but I wrote something that fits my need. It's not perfect, I have to work on it but is a begin:
#define UNIQUE(T) unsigned int GetID(){return UniqueType<T>::id();}
struct UniqueTypeBase
{
static unsigned int _ids;
};
unsigned int UniqueTypeBase::_ids = 0;
template <class T>
struct UniqueType : public UniqueTypeBase
{
static const unsigned int id()
{
static unsigned int typeId = 0;
if (typeId == 0)
typeId = ++_ids;
return typeId;
}
};
template <class T>
class TemplateBean
{
public:
T m_tValue;
template<class T> set_(T){return false;}
template<class T> get_(T&){return false;}
bool set_(T value){ m_tValue = value; return true;}
bool get_(T& value) { value = m_tValue;return true;}
};
class Prova : public TemplateBean<int>
{
public:
UNIQUE(Prova)
Prova(){m_tValue = 0;}
};
class Prova2 : public TemplateBean<float>
{
public:
UNIQUE(Prova2)
Prova2(){m_tValue = 0;}
};
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class Item, class ReturnValue>
bool Get(ReturnValue & val)
{
Item a;
map<unsigned int, void*>::iterator it;
it = m_TagMap.find(a.GetID());
if(it != m_TagMap.end())
{
Item* pItem = reinterpret_cast<Item*>(it->second);
if(pItem->get_(val))
return true;
}
return false;
}
template <class Item, class Value>
bool Set(Value val)
{
Item* pBean = new Item();
if(pBean->set_(val))
{
m_TagMap[pBean->GetID()] = (void*)pBean;
return true;
}
return false;
}
protected:
map<unsigned int, void*> m_TagMap;
};
Test Main:
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed\n");
if(!msg.Set<Prova,float>(4.00))
printf("Test 2 succed\n");
if(msg.Set<Prova2,float>(4.00))
printf("Test 3 succed\n");
int a=0;
if(msg.Get<Prova>(a))
printf("%d = 4...if 4=4 test passed\n",a);
float b=0;
if(msg.Get<Prova2>(b))
printf("%f = 4...if 4=4 test passed\n",b);
getchar();
}
I think you misunderstood the use of templates.
Templates are blueprints to build classes or methods, that the compiler use to produce real classes and methods (which is called instantiation).
As such, they are purely a compile-time facility. Therefore, they cannot be virtual, and thus overloading a template method in a derived class does not mean what you expect. It hides the base class method when used from derived (statically) but you still call the base class method if you use a reference or pointer to the base class.
What you are trying to achieve is, unfortunately, impossible with templates: it requires a runtime check.
Furthermore, you are using a std::vector<Bean> which will not work as intended. Polymorphic types shall not be manipulated by values in C++, you need a std::vector< std::unique_ptr<Bean> > or boost::ptr_vector<Bean>...
I would recommend reading a good C++ primer before attempting the kind of task you have set yourself upon. You need a basic introduction to C++ paradigms... and gotchas. And there are a lot of gotchas.