I have a non-templatized class (Par_list_elem), and I would like to give access to its internals to the class Par_list (to build an intrusive list).
The catch: I need Par_list_elem and all of its subclasses to be accessible to Par_list. In detail, the only fields that need to be accessible are _next and _prev; explicitly limiting to those fields would be nice, but isn't required.
I've made a few preliminary attempts at doing this, the latest of which is below:
template <class T> class Par_list {
public:
Par_list() : _head(0) {}
~Par_list();
//Insert element into list
bool insert(T elem);
//Remove element identified by iterator
void erase(iterator itr);
private:
T* _head;
};
class Par_list_elem {
public:
Par_list_elem() : _next(0), _prev(0) {}
//Get next element in list
Par_list_elem* next() { return _next; }
private:
Par_list_elem* _next;
Par_list_elem* _prev;
template <typename> friend class Par_list;
};
template <class T> void Par_list<T>::erase(Par_list<T>::iterator itr) {
T* e = *itr;
T* p;
if ((p = e->_prev) != 0)
p->_next = e->_next;
else
_head = e->_next;
if ((e->_next) != 0)
(e->_next)->_prev = p;
delete e;
}
template <class T> bool Par_list<T>::insert(T* nelem) {
T* curr = _head;
if (curr != 0) {
while (curr->_next != 0)
curr = curr->next();
curr->_next = nelem;
} else
_head = nelem;
nelem->_prev = curr;
nelem->_next = 0;
return true;
}
test.cpp
#include "parsnip_list_back.h"
class elem : parsnip::Par_list_elem {
int _elem;
};
int main (int argc, char** argv) {
parsnip::Par_list<elem> plist;
return 0;
}
Some information seems to be available here:
Template friend
But the goal is different in enough detail that I'm stuck.
Thanks!
--------UPDATE---------
The following sort of error occurs for each instance of an access of a private member of Par_list_elem. I'm compiling on gcc 4.4.
parsnip_list_back.h:66: error: ‘parsnip::Par_list_elem* parsnip::Par_list_elem::_prev’ is private
parsnip_list_back.h:124: error: within this context
So, with the current implementation, even the superclass isn't giving up its privates.
The problem is that you're inheriting privately from Par_list_elem. So, although Par_list can access private members of the base class, it cannot access the base class itself.
I need Par_list_elem and all of its subclasses to be accessible to Par_list.
This would solve the problem if it were possible, but it can't be done; friendship isn't inherited.
The simplest solution is to inherit publicly.
Related
There is a similar question to this with the function being an operator overload with arguments and that is the main emphasis, which is only confusing me further.
I am simply trying to execute a short recursive function on a tree class that gets called on non-empty Node objects in order to traverse down the tree's child nodes respectively.
My class declarations are as such:
template<class T>
class BTNode {
template<class I>
friend class BST;
T data;
BTNode<T>* left_;
BTNode<T>* right_;
...
}
template<class I>
class BST {
BTNode<I>* root_;
BTNode<I>* curr_;
BTNode<I>* parent_;
int currSize = 0;
public:
size_t size() const {
if (root_ == NULL) {
return currSize;
}
else {
BTNode<I>* left_ = root_->getLeft();
BTNode<I>* right_ = root_->getRight();
if (left_ != NULL)
currSize += left_->size();
if (right_ != NULL)
currSize += right_->size();
}
return currSize;
}
...
};
The error as it stands is:
'size()': is not a member of 'BTNode<I>'
So far, I have tried make BTNode a friend class of BST, and the error still prevails (having both classes become friends of each other).
Thanks in advance.
You misunderstand what friend declarations do. Saying that A is a friend of B means that A gains access to protected and private members of B. It allows A to call private functions of B, for example. It does not extend the interface of A or B in any way.
If I understand correctly what you're trying to achieve, you should be able to do that by having size take a parameter:
template<class I>
class BST {
BTNode<I>* root_;
BTNode<I>* curr_;
BTNode<I>* parent_;
public:
size_t size() const {
return size_(root_);
}
private:
static size_t size_(const BTNode<I> *node) {
if (node == NULL) {
return 0;
}
else {
return 1 + size_(node->getLeft()) + size_(node->getRight());
}
}
...
};
As far as I can understand, linked list can only implemented with an outsider class. Because a class can't have a member varable of it's own type and a node list need that type. The problem is, if the link is intented to be used by a specific class. If, the link class created outside, it will be available to be created as a standalone object.
It's okay if the link class/struct is a pure link object because it can be used for linking another object type. But, in case I need a link that has a functionallity that only related to a certain object, the public availability of it will be pointless. And I think it's better to be created as a private.
Let's take a look at this declaration:
#include <unordered_map>
using namespace std;
template<class T>
class Node
{
public:
Node();
Node(const T& item, Node<T>* ptrnext = NULL);
T data;
// access to the next node
Node<T>* NextNode();
// list modification methods
void InsertAfter(Node<T>* p);
Node<T>* DeleteAfter();
Node<T> * GetNode(const T& item, Node<T>* nextptr = NULL);
private:
Node<T> * next;
unordered_map<string, T*> nodeList;
};
The unordred_map<string,T*> member can only have meaning with a certain object. So, it will be pointless for Node class to be available outside.
Is it possible? Or maybe is it a bad idea to add a non-generic funtionallity for link class?
class A {
A* m_pnext = nullptr;
public:
inline A* next() { return m_pnext; }
inline void set_next(A*ptr) { m_pnext = ptr; }
}
template <class type>
class LinkedList {
type *m_pfirst = nullptr;
public:
void add(type * ptr) {
if ( nullptr == m_pfirst ) {
m_pfirst = ptr;
} else {
type * n = m_pfirst, p = m_pfirst->next;
while (nullptr != p) {
n = p;
p = n->next();
}
n->set_next(ptr);
}
}
};
Plenty of room for improvement, of course. I'll let you exercise your mind.
Im trying to make a class to use in a Library, and im not sure if its even possible to do. The idea of this class, is to provide methods to insert, search and delete items on a list, but my main problem is that, as i dont know the type of object that i want to place in a list, I dont know how to work with it. I thought I could place a void pointer, and then make it point to a structure, but I havent been able to make it work.
Lets suppose my class is something like this:
class ListManager
{
private:
void* FirstItem;//This would point to the first item of the list
void* LastItem;//This would point to the last item of the list
public:
void AddItemToList(void* Item);
void RemoveItemFromList(void* Item);
}
So, the idea would be that, from my program, I can define a structure like
struct Employee
{
*char Name;
int Id;
int PhoneNumber;
}
And then, use this class, to be able to add/delete Employees. So in this case, the void* pointers, should be pointing to a struct of the type Employee. Nevertheless, i want to make my class work for any type of struct.
I dont know if i explained exactly what I want to do, I tried several ways of doing this, and failed on all of them.
Im going to post a code of how I would like the class to work, if I havent explained myself correctly
ListManager *Worker;
Worker=new(ListManager);
Employee *Item;
Item=new (Employee);
Item->Id=126;
Item->PhoneNumber=42154872;
Worker->AddItemToList(Item);
/*At this point, FirstItem and LastItem should point to the Item i just created*/
Could someone point me in the right direction, as how to make a class work with a structure, without knowing the type of structure?
Thanks in advance
You need templates!
here's a simple interface that you can start working with.
template <typename T>
class ListManager
{
public:
void addItemToList(const T& item);
void removeItemFromList(const T& item);
}
Now T is your type, and you'd declare a ListManager like this:
ListManager<Employee> manager;
I would suggest you also to look at the stl documentation/implementation of a list at: http://www.cplusplus.com/reference/list/list/
You have also the concept of iterators to dig into.
Also, try to use values instead of pointers. With the interface I gave you, you would store the actual value in the list and not a pointer, so the list owns the object and you won't need to manage your memory manually.
See this Tutorial:
http://www.tutorialspoint.com/cplusplus/cpp_templates.htm
Your Example could be look like:
#include <iostream>
using namespace std;
template <class T>
class ListManager
{
private:
void* FirstItem;//This would point to the first item of the list
void* LastItem;//This would point to the last item of the list
public:
void AddItemToList(const T& Item){
std::cout << Item << std::endl;
};
void RemoveItemFromList(const T& Item){};
};
int main() {
ListManager<std::string> mgr;
mgr.AddItemToList("Test");
return 0;
}
Output:
Test
Working Example:
http://ideone.com/FCAtcJ
There really are no interfaces in C++, but you could use a class template just the same way:
template <typename T>
class ListInterface {
public:
void add(T * item) { list.push_back( item); }
void remove(T * item) { list.erase(std::find(list.begin(), list.end(), item)); }
T * get(int index) { return list[index]; }
int size() const { return list.size(); }
private:
std::vector<T *> list;
};
class Manager : public ListInterface<Employee> {
// ...
};
Naturally, this is a barebone example, you really outta do some checking in the remove() and get() methods.
There are multiple solutions to this problem.
Simply use std::list
std::list<Employee> manager;
If 1. is not possible you can define your own list interface using template
template <class T>
class ListManager
{
private:
class Iterator {
public:
T& item;
Iterator* next;
Iterator* prev;
Iterator(T& i, Iterator* n, Iterator* p) : item(i), next(n), prev(p) {}
}
Iterator* FirstItem = NULL;//This would point to the first item of the list
Iterator* LastItem = NULL;//This would point to the last item of the list
public:
void AddItemToList(T& Item) {
if(LastItem) {
Iterator* it = new Iterator{Item, NULL, LastItem};
LastItem->next = it;
LastItem = it;
} else {
Iterator* it = new Iterator{Item, NULL, NULL};
FirstItem = it;
LastItem = it;
}
}
void RemoveItemFromList(const T& Item) {
for(Iterator* it = FirstItem; it != NULL; it = it->next) {
if(it->item == Item) {
if(it->prev)
it->prev->next = it->next;
else
FirstItem = it->next;
if(it->next)
it->next->pref = it->pref;
else
LastItem = it->pref;
delete it;
break;
}
}
}
};
If 1. and 2. is not possible because you need need multiple types inside your list. You can either use a list of Anys (like boost::Any) or a unsafe version with void*:
class ListManager
{
private:
class Iterator {
public:
void* item;
Iterator* next;
Iterator* prev;
Iterator(void* i, Iterator* n, Iterator* p) : item(i), next(n), prev(p) {}
}
Iterator* FirstItem = NULL;//This would point to the first item of the list
Iterator* LastItem = NULL;//This would point to the last item of the list
public:
template<class T>
void AddItemToList(T& Item) {
if(LastItem) {
Iterator* it = new Iterator{&Item, NULL, LastItem};
LastItem->next = it;
LastItem = it;
} else {
Iterator* it = new Iterator{&Item, NULL, NULL};
FirstItem = it;
LastItem = it;
}
}
template<class T>
void RemoveItemFromList(const T& Item) {
for(Iterator* it = FirstItem; it != NULL; it = it->next) {
if(it->item == &Item) {
if(it->prev)
it->prev->next = it->next;
else
FirstItem = it->next;
if(it->next)
it->next->pref = it->pref;
else
LastItem = it->pref;
delete it;
break;
}
}
}
};
Code is not tested
***UPDATE****
so to start I am trying to attempt hashing. to try to make it short, I created a linkedlsit class which takes in a generic parameter . I have a hashtable class where I attempted to create (i believe) a array of linkedlist pointers (keeping in mind the linkedlist takes a generic type )
so, in my hashtable class, I have a private variable such that
SLL< Entry <string, int> >** list;
where SLL is my linked list, Entry is the object that holds a key (string) and value (int) and tying to make it a array of pointers.
in the hashtable constructor i create it like this
list = new SLL<Entry<string, int> > * [this->size];
now in my code, i attempt to append the Entry object into the array after my hashcode function ends
list[hash]->append(new Entry<string, int>(key, e));
however it get this error
HashTable.h: In member function 'void HashTable::createEntry(std::string, int)':
HashTable.h:78:53: error: no matching function for call to 'SLL<Entry<std::basic_string<char>, int> >::append(Entry<std::basic_string<char>, int>*)'
list[hash]->append(new Entry<string, int>(key, i));
it works if i replace Entry as the object within the linkedlist as jsut an int, or float, or even string
so what can be causing this? please and thank you, if you need any more info, let me know :)
#ifndef SLL_H
#define SLL_H
template <class T>
class SLL
{
private:
Node<T>* head;
Node<T>* tail;
int size;
public:
SLL();
virtual ~SLL();
void append(T&);
void append(T*);
void prepend(T);
void deleteElem(int);
void toString();
int getSize();
void insertAt(T, int);
T retrieveDataAt(int);
};
#endif /* SLL_H */
template <class T>
SLL<T>::SLL()
{
this->tail = NULL;
this->head = NULL;
this->size = 0;
}
void SLL<T>::append(T data)
{
//do stuff
this->head = new Node<T>(data);;
}
There's a couple of issues with the code you posted, and it just goes to show
that when using templates you need to be sure everything matches up nicely.
Especially because the compiler will not even care about some types of errors
until you actually instantiate a template with a certain type.
The first is that your class SLL<T> declares a number of member functions,
two of which are SLL::append(T&) and SLL::append(T*). The problem is that in
the example code you posted, the member function you are defining is
SLL::append(T), which doesn't exist!
The second is that because new returns a pointer to a type, your code:
list[hash]->append(new Entry<string, int>(key, e));
is equivalent to
Entry<string, int>* data_ptr = new Entry<string, int>(key, e);
list[hash]->append(data_ptr);
which will look for a member function of the form SLL::append(T*) not
SLL::append(T), and no such function has been defined!
Here's some minimally working code that should compile for you. Note that I
used std::pair instead of Entry for brevity and that you'll need to compile with a
-std=c++11 or equivalent flag (e.g. g++ -std=c++11 main.cpp) since I used nullptr:
#include <utility>
#include <string>
template<class T>
class SLL;
// singly linked list node
template<class T>
class Node
{
private:
Node<T> *next;
T data;
friend class SLL<T>;
public:
Node(T input) : next(nullptr),
data(input) {}
~Node() {delete next;}
};
// the singly linked list class
template <class T>
class SLL
{
private:
Node<T>* head;
Node<T>* tail;
std::size_t size;
public:
SLL() : head(nullptr),
tail(nullptr), size(0) {}
~SLL() {delete head;}
std::size_t getSize() const {
return size;}
void append(T data);
};
template<class T>
void SLL<T>::append(T data)
{
Node<T> *temp = new Node<T>(data);
if (!head)
head = temp;
if (tail)
tail->next = temp;
tail = temp;
size += 1;
}
int main()
{
// less typing
using list_type = SLL<std::pair<std::string, int>>;
// allocation for the list of lists
std::size_t hash_size = 10;
list_type** list_of_lists = new list_type*[hash_size]();
// data to input
std::string key = "key";
int value = 9330323;
std::size_t hash = 4;
// check and append
if (!list_of_lists[hash])
list_of_lists[hash] = new list_type;
list_of_lists[hash]->append(std::pair<std::string, int>(key, value));
// cleanup
for (std::size_t i = 0; i < hash_size; ++i)
delete list_of_lists[i];
delete[] list_of_lists;
}
I am creating a class LinkedList. I am having difficulty adding another node to my list.
Here is what I have so far:
template<typename T>
class LinkedList
{
private:
T element;
T *next;
public:
LinkedList();
LinkedList(T element);
void add(LinkedList<T> &otherList);
void print();
};
template<typename T>
LinkedList<T>::LinkedList()
{
next = NULL;
}
template<typename T>
LinkedList<T>::LinkedList(T element)
{
this->element = element;
next = NULL;
}
template<typename T>
void LinkedList<T>::add(LinkedList<T> &otherList)
{
next = &otherList;
}
template<typename T>
void LinkedList<T>::print()
{
LinkedList<T> *current = this;
while (current != NULL)
{
std::cout << current->element;
current = current->next;
}
}
int main()
{
LinkedList<std::string> myFirst("First");
LinkedList<std::string> mySecond("Second");
myFirst.add(mySecond);
myFirst.print();
return 0;
}
This works however if I make the change:
void add(const LinkedList<T> &otherList);
template<typename T>
void LinkedList<T>::add(const LinkedList<T> &otherList)
{
next = &otherList; //now an error right here
}
Then I get an error stating:
Assigning to 'LinkedList<std::__1::basic_string<char> > *' from incompatible type 'const LinkedList<std::__1::basic_string<char> > *'
Why is it I get this error?
next is a T*, and you're trying to assign a const LinkedList<T>* to it.
I suppose you meant something like next = &(otherList.element) (though even then I think your list semantics are somewhat broken — elements shouldn't typically be shared by multiple containers unless you're very, very clear about the ownership semantics).
Contrary to your claims, your first program doesn't work either for the same reason.