Trying to initialize a class called StackAsLinkedList, which should be a derived class of the abstract class Stack (testing code which is available here: http://www.brpreiss.com/books/opus4/).
However, I get an error trying to instantiate this code in main():
StackAsLinkedList stack;
error C2259: 'StackAsLinkedList' : cannot instantiate abstract class
I am confused about this, because I thought StackAsLinkedList is defined as a derived class of Stack:
#ifndef STACK_H
#define STACK_H
#include "object.h"
#include "linkList.h"
#include "container.h"
class Stack : public virtual Container
{
public:
virtual Object& Top () const = 0;
virtual void Push (Object&) = 0;
virtual Object& Pop () = 0;
};
class StackAsLinkedList : public Stack
{
LinkedList<Object*> list;
class Iter;
public:
StackAsLinkedList () : list() {}
~StackAsLinkedList() { Purge(); }
//
// Push, Pop and Top
//
void Push(Object& object);
Object& Pop();
Object& Top() const;
//
// purge elements from, and accept elements onto, the list
//
void Purge();
void Accept (Visitor&) const;
friend class Iter;
};
class StackAsLinkedList::Iter : public Iterator
{
StackAsLinkedList const& stack;
ListElement<Object*> const* position;
public:
Iter (StackAsLinkedList const& _stack) : stack(_stack) { Reset(); }
//
// determine whether iterator is pointing at null
//
bool IsDone() const { return position == 0; }
//
// overloaded dereference and increment operator
//
Object& operator*() const;
void operator++() const;
void Reset() { position = stack.list.Head(); }
};
#endif
The implementation:
#include "stack.h"
void StackAsLinkedList::Purge()
{
if ( IsOwner() )
{
ListElement<Object*> const* ptr;
for(ptr = list.Head(); ptr != 0; ptr = ptr->Next() )
delete ptr->Datum();
list.Purge();
count = 0;
}
}
void StackAsLinkedList::Push(Object& object)
{
list.Prepend(&object);
++count;
}
Object& StackAsLinkedList::Pop()
{
if(count == 0)
throw domain_error ("stack is empty");
Object& result = *list.First();
list.Extract(&result);
--count;
return result;
}
Object& StackAsLinkedList::Top() const
{
if(count == 0)
throw domain_error ("stack is empty");
return *list.First();
}
void StackAsLinkedList::Accept(Visitor& visitor) const
{
ListElement<Object*> const* ptr;
for(ptr = list.Head(); ptr != 0 && !visitor.IsDone(); ptr = ptr->Next())
visitor.Visit(*ptr->Datum());
}
class Container:
#ifndef CONTAINER_H
#define CONTAINER_H
#include "object.h"
#include "visitor.h"
#include "iterator.h"
#include "ownership.h"
class Container : public virtual Object, public virtual Ownership
{
protected:
unsigned int count;
Container () : count(0) {}
public:
virtual unsigned int Count () const { return count; }
virtual bool IsEmpty () const { return Count () == 0; }
virtual bool IsFull () const { return false; }
//virtual HashValue Hash () const;
virtual void Put (ostream&) const;
virtual Iterator& NewIterator () const { return *new NullIterator (); }
virtual void Purge () = 0;
virtual void Accept (Visitor&) const = 0;
};
#endif
EDIT: It appears that the compiler says that the CompareTo() method in Object is not implemented in any of the derived classes. However, this functionality is implemented in the derived class of Object called "Wrapper":
#ifndef WRAPPER_H
#define WRAPPER_H
#include "object.h"
template <class T>
class Wrapper : public Object
{
protected:
T datum;
int CompareTo (Object const&) const;
public:
Wrapper ();
Wrapper (T const&);
Wrapper& operator = (T const&);
operator T const& () const;
//HashValue Hash () const;
void Put (ostream&) const;
};
//
// typedefs for for Wrappers representing different primitive
// data types
//
typedef Wrapper <int> Int;
typedef Wrapper <char> Char;
typedef Wrapper <double> Double;
typedef Wrapper <std::string> String;
#include "wrapper.inc"
#endif
But Stack doesn't inherit from Wrapper - so I am guessing this means another CompareTo method needs to be implemented for Stack? Not sure how the original author got this to work (scratches head).
Since you've now explained you're trying to fix it, I suggest:
First step is to get it compiling, which you can do by adding a CompareTo(Object&) const member to StackAsLinkedList. You can use either dynamic_cast or the Visitor machinery to find out whether the object compared to is another collection.
Next, get rid of reference parameters in any case where the object will be stored by the callee and used after the function returns. And eradicate reference return types, where ownership is being transferred. You can either use pointers, or change the collection to pass-by-value (but don't pass-by-value if the collection should be polymorphic). You'd get:
class Stack : public virtual Container
{
public:
virtual Object& Top () const = 0; // short-term access to object, no ownership transfer, reference is ok here.
virtual void Push (Object*) = 0; // pointer kept, ownership transfer, use pointer
virtual Object* Pop () = 0; // ownership transfer (caller must delete), use pointer
};
Then, you should do something about the brokenness in the Visitor implementation. Right now, Accept always calls Visit(Object&) regardless of the dynamic type. You'd need to call a virtual Accept function on each individual member, in order to let the Visitor perform correctly on polymorphic collections.
We're well on the way to scrapping the design by this point.
Related
Edit: I had copied the base template for the statisticscompiler class from another solution, and it seems I somehow had ended up editing the original one while including the new one (that hadn't been edited yet) which is what led to the errors. So a tale of caution against copy pasting code into another file with the same name.
I will just post the header files because I think that's what matters here, let me know if otherwise and I can post the cpp. I have one base class that collects statistics from a process, with two derived classes and then a class that let's me use several statistics classes at once
Statistics.h
#pragma once
#define STATISTIC_H
#include <vector>
#include "Arrays.h"
class Statistics
{
public:
Statistics() {}
virtual void DumpOnePath(MJArray results) = 0;
virtual std::vector<std::vector<double>> GetResultsSoFar() const = 0;
virtual Statistics* clone() const = 0;
virtual ~Statistics() {}
private:
};
class StatisticsMean : public Statistics
{
public:
StatisticsMean();
virtual void DumpOnePath(MJArray results) ;
virtual std::vector<std::vector<double>> GetResultsSoFar() const ;
virtual Statistics* clone() const;
private:
MJArray RunningSums;
unsigned long PathsDone;
};
class StatisticsQuantiles : public Statistics
{
public:
StatisticsQuantiles(double p_lower_, double p_upper_);
virtual void DumpOnePath(MJArray results);
virtual std::vector<std::vector<double>> GetResultsSoFar() const;
virtual Statistics* clone() const;
private:
std::vector<MJArray> RunningResults;
unsigned long PathsDone;
double p_lower;
double p_upper;
};
StatisticsCompiler.h
#pragma once
#define STATISTICS_COMPILER_H
#include "statistics.h"
#include "wrapper.h"
class StatisticsCompiler : public Statistics
{
public:
StatisticsCompiler(const std::vector <Wrapper<Statistics>>& Inner_);
virtual Statistics* clone() const;
virtual void DumpOnePath(MJArray results);
virtual std::vector<std::vector<double>> GetResultsSoFar() const;
private:
std::vector <Wrapper<Statistics>> Inner;
};
And in my main class I'm trying to do this:
StatisticsMean meanGatherer;
StatisticsQuantiles quantileGatherer(p_lower, p_upper);
vector<Wrapper<Statistics>> gathererArray{ meanGatherer, quantileGatherer};
StatisticsCompiler meanAndQuantileGatherer(gathererArray);
Which gives an error no the last line complaining that "No instance of constructor matches the argument list. Argument types are:
(std::vector<Wrapper<Statistics>, std::allocator<Wrapper<Statistics>>>)."
But isn't that exactly what I've defined the constructor to accept? at least the first part, I don't know what
std::allocator<Wrapper<Statistics>>
means.
Wrapper.h in case needed. It does the memory handling
#pragma once
#define WRAPPER_H
template< class T>
class Wrapper
{
public:
Wrapper()
{
DataPtr = 0;
}
Wrapper(const T& inner)
{
DataPtr = inner.clone();
}
~Wrapper()
{
if (DataPtr != 0)
delete DataPtr;
}
Wrapper(const Wrapper<T>& original)
{
if (original.DataPtr != 0)
DataPtr = original.DataPtr->clone();
else
DataPtr = 0;
}
Wrapper& operator=(const Wrapper<T>& original)
{
if (this != &original)
{
if (DataPtr != 0) {
delete DataPtr;
}
DataPtr = (original.DataPtr != 0) ? original.DataPtr->clone() : 0;
}
return *this;
}
T& operator*()
{
return *DataPtr;
}
const T& operator*() const
{
return *DataPtr;
}
const T* const operator->() const
{
return DataPtr;
}
T* operator->()
{
return DataPtr;
}
private:
T* DataPtr;
};
I implemented the following smart pointer template class:
#ifndef __ProjectManager__mSharedPtr__
#define __ProjectManager__mSharedPtr__
#include <stdio.h>
#include "RefCount.h"
template <class T>
class mSmartPtr {
T *data;
RefCount *rc;
public:
mSmartPtr(T* srcPtr);
mSmartPtr(const mSmartPtr&);
~mSmartPtr();
T* operator->() const;
T& operator*() const;
mSmartPtr<T>& operator=( mSmartPtr&);
mSmartPtr<T> operator()(mSmartPtr&);
};
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator()(mSmartPtr<T>& src) {
return dynamic_cast<??>(src);
}
template <class T>
mSmartPtr<T>::mSmartPtr(T *srcPtr):
data(srcPtr) {
rc = new RefCount();
rc->add();
}
template<class T>
mSmartPtr<T>::~mSmartPtr() {
if (rc->remove() == 0) {
delete data;
delete rc;
}
}
template<class T>
mSmartPtr<T>::mSmartPtr(const mSmartPtr<T> &src):
data(src.data), rc(src.rc) {
rc->add();
}
template <class T>
T* mSmartPtr<T>::operator->() const {
return data;
}
template<class T>
T& mSmartPtr<T>::operator*() const {
return &data;
}
template <class T>
mSmartPtr<T>& mSmartPtr<T>::operator=( mSmartPtr<T> &src) {
if (this != &src) {
if (rc->remove() == 0) {
delete data;
delete rc;
}
data = src.data;
rc = src.rc;
rc->add();
}
return *this;
}
#endif /* defined(__ProjectManager__mSharedPtr__) */
let's say my application contains the following classes:
class Base
{
protected:
...
public:
virtual ~Base() =0;
...
};
class Derived1 : public Base
{
protected:
...
public:
virtual ~Derived1() {}
...
};
class Derived2 : public Base
{
protected:
...
public:
virtual ~Derived2() {}
...
};
and I need store data at the following way:
int int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Derived1> d1 = foo();
v.push_back(d1);
return 0;
}
I need to fix somehow the cast operator, but how? how do I get the base class in the dynamic cast?
#Guvante
Your code did not work , I modified it as follows but I don't know if will work well
template<class T>
mSmartPtr<T> mSmartPtr<T>::operator ()(mSmartPtr<T>& src) {
mSmartPtr<T> retVal(dynamic_cast<T*>(src.data));
retVal.rc = src.rc;
retVal.rc.Add();
return retVal;
}
I think there is a better alternative to this. Unless you have a different location where you need to be able to do this, you can avoid the headache by changing the way you create the object.
int main(int argc, char const *argv[])
{
std::vector<mSmartPtr<Base>> v;
mSmartPtr<Base> d1 = static_cast<Base*>(foo());
v.push_back(d1);
return 0;
}
Just avoid creating an mSmartPtr that is typed differently than your vector.
In your conversion method extract the underlying pointer and cast it then put it into the new smart pointer. Don't forget to copy the RefCount and ensure that your target class has a virtual destructor (so the correct one gets called no matter which smart pointer gets dispossed last).
I couldn't figure out how to define it externally but an inline definition worked.
//In the definition, replacing this line
//mSmartPtr<T> operator()(mSmartPtr&)
template<class Tdest>
operator mSmartPtr<Tdest>() {
mSmartPtr<Tdest> retVal(static_cast<Tdest*>(data));
retVal.rc = rc;
retVal.rc.Add();
return retVal;
}
In theory you could also add a version that takes a r-value if you are using C++11 but I think that would take a little work to do correctly so I avoided it.
I am making a class that shares data between several objects using dynamic memory. The relevant parts of the class are shown below.
class StrBlob
{
public:
StrBlob::StrBlob(std::initializer_list<std::string> il) :
data(std::make_shared<std::vector<std::string>>(il)) {}
void push_back(const std::string &t) const { data->push_back(t); }
private:
std::shared_ptr<std::vector<std::string>> dataPtr;
};
I understand that by making push_back a const member function, I am saying that this function will not change the member dataPtr. However, the underlying vector that dataPtr points to is not const, as shown by the below code.
//The result is foo = {"bar", "foobar"}
const StrBlob foo = {"bar"};
foo.push_back("foobar");
Is it possible or even desirable to make the underlying vector const by making the StrBlob object const? Should be something like making dataPtr a pointer to const when the object is const, but I'm not sure how to achieve that.
You can make a thin wrapper around std::shared_ptr (details omitted like ctor etc):
#include <memory>
template< class T > class const_propagated_shared_ptr {
std::shared_ptr<T> m_ptr;
public:
T &operator*() { return m_ptr.operator*(); }
T* operator->() { return m_ptr.operator->(); }
const T &operator*() const { return m_ptr.operator*(); }
const T *operator->() const { return m_ptr.operator->(); }
};
class Foobar {
const_propagated_shared_ptr<int> m_ptr;
public:
void f1() { *m_ptr = 10; }
void f2() const { *m_ptr = 10; } // compile error
};
But as this is implementation detail of the class (Foobar in this case) I am not sure that it worse the effort, as to let modify data by const method or not can be controlled by class designer.
I have a hash table template that I have written for a class. I have a project due that relies on utilizing this hash table. It accepts an unsigned integer value to initialize the number of buckets it has, as well as a hash function to point to. I have not written that hash function yet, but I have a declaration for it. When I try to use the member initializer in my Game class for the hash table data member, it gives me an error that I don't understand.
Error 1 error C3867: 'Game::xorHash': function call missing argument list; use '&Game::xorHash' to create a pointer to member
2 IntelliSense: no instance of constructor "HTable<Type>::HTable [with Type=std::string]" matches the argument list
argument types are: (int, unsigned int (const std::string &s))
my Hash Table class is as follows:
#pragma once
#include "SLList.h"
template<typename Type> class HTable
{
public:
HTable(unsigned int numOfBuckets, unsigned int (*hFunction) (const Type &v));
~HTable();
HTable<Type>& operator=(const HTable<Type>& that);
HTable(const HTable<Type>& that);
void insert(const Type& v);
bool findAndRemove(const Type& v);
void clear();
int find(const Type& v) const;
private:
SLList<Type>* ht;
unsigned int (*hFunct) (const Type &v);
unsigned int numOfBuck;
};
template<typename Type>
HTable<Type>::HTable(unsigned int numOfBuckets, unsigned int (*hFunction) (const Type &v))
{
ht = new SLList<Type>[numOfBuckets];
this->numOfBuck = numOfBuckets;
this->hFunct = hFunction;
}
template<typename Type>
HTable<Type>::~HTable()
{
delete [] ht;
ht = nullptr;
}
template<typename Type>
HTable<Type>& HTable<Type>::operator=(const HTable<Type>& that)
{
if(this != &that)
{
delete [] this->ht;
this->hFunct = that.hFunct;
this->numOfBuck = that.numOfBuck;
this->ht = new SLList<Type>[numOfBuck];
for(unsigned int i = 0; i < this->numOfBuck; i++)
this->ht[i] = that.ht[i];
}
return *this;
}
template<typename Type>
HTable<Type>::HTable(const HTable<Type>& that)
{
this = *that;
}
template<typename Type>
void HTable<Type>::insert(const Type& v)
{
ht[hFunct(v)].addHead(v);
}
template<typename Type>
bool HTable<Type>::findAndRemove(const Type& v)
{
SLLIter<Type> iter(ht[hFunct(v)]);
for(iter.begin(); !iter.end(); ++iter)
{
if(v == iter.current())
{
ht[hFunct(v)].remove(iter);
return true;
}
}
return false;
}
template<typename Type>
void HTable<Type>::clear()
{
for(unsigned int i = 0; i < this->numOfBuck; ++i)
ht[i].clear();
}
template<typename Type>
int HTable<Type>::find(const Type& v) const
{
SLLIter<Type> iter(ht[hFunct(v)]);
for(iter.begin(); !iter.end(); ++iter)
{
if(v == iter.current())
return hFunct(v);
}
return -1;
}
My Game.h:
#pragma once
#include "stdafx.h"
#include "HTable.h"
#include "BST.h"
#include "DTSTimer.h"
using namespace std;
class Game
{
public:
Game(void);
virtual ~Game(void);
void refresh();
void input();
unsigned int xorHash(const string &s);
private:
string userInput;
DTSTimer timer;
BST<string> answers;
HTable<string> dictionary;
};
My Game.cpp (this is obviously just a skeleton, since I can't get the member init to work)
#include "Game.h"
Game::Game(void) : dictionary(2048, xorHash)
{
}
Game::~Game(void)
{
}
void Game::refresh()
{
}
void Game::input()
{
}
unsigned int Game::xorHash(const string &s)
{
return 0;
}
I've been working on this for a good while, and have been hitting a wall. I would really appreciate some help on how to get this thing up and running. Let me know if there is another snippet that needs to be seen (I've tried to be thorough in that regard).
You have two problems. The first is that you don't pass the member function pointer properly (the error message tells you exactly what do do). The other problem is that a function pointer is not the same as a member function pointer.
A member function pointer needs an instance object object to call the member function on. And this instance is passed as a hidden first argument, something that normal functions don't have.
For this you might instead turn to std::function and std::bind:
class HTable
{
public:
HTable(unsigned int numOfBuckets, std::function<unsigned int(const Type&)> hFunction);
...
private:
std::function<unsigned int(const Type&)> hFunct;
...
};
Then
Game::Game(void) : dictionary(2048, std::bind(&Game::xorHash, this))
{
}
I am new to C++. Could you pls help me get rid of the errors:
error C2259: 'MinHeap' : cannot instantiate abstract class
IntelliSense: return type is not identical to nor covariant with return type "const int &" of overridden virtual function function
template <class T> class DataStructure {
public:
virtual ~DataStructure () {}
virtual bool IsEmpty () const = 0;
virtual void Push(const T&) = 0;
virtual const T& Top() const = 0;
virtual void Pop () = 0;
};
class MinHeap : public DataStructure<int>
{
private:
std::vector<int> A;
public:
bool IsEmpty() const
{
..
}
int Top() const
{
..
}
void Push(int item)
{
...
}
void Pop()
{
..
}
};
The problem is with const T& Top() vs. int Top(). The latter is different from the former, and thus not an override. Instead it hides the base class function. You need to return exactly the same as in the base class version: const int& Top() const.
The same problem exists for Push(), BTW.
try
class MinHeap : public DataStructure<int>
{
private:
std::vector<int> A;
public:
bool IsEmpty() const
{
..
}
const int& Top() const
{
..
}
void Push(const int& item)
{
...
}
void Pop()
{
..
}
};
Note that it is using const int& instead of int for Top and Push