Связной список с разными типами данных
#pragma once;
template <class NTYPE>
class List;
template <class NTYPE>
class ListNode
{
friend class List<NTYPE>;
public:
ListNode (const NTYPE &);
NTYPE getData();
private:
NTYPE data;
ListNode *nextPtr;
};
////////////////////////////////////
template <class NTYPE>
ListNode<NTYPE>::ListNode(const NTYPE &info)
{
data = info;
nextPtr = 0;
}
////////////////////////////////////
template <class NTYPE>
NTYPE ListNode<NTYPE>::getData()
{
return data;
}
#pragma once;
#include <iostream>
using namespace std;
#include <assert.h>
#include "listnd.h"
template <class NTYPE>
class List
{
public:
List();
~List();
void insertAtFront(const NTYPE &);
void insertAtBack(const NTYPE &);
//int removeFromFront(NTYPE &);
//int removeFromBack(NTYPE &);
int isEmpty();
void print();
private:
ListNode<NTYPE> *firstPtr;
ListNode<NTYPE> *lastPtr;
ListNode<NTYPE> * getNewNode(const NTYPE &);
};
////////////////////////////////////
template <class NTYPE>
List<NTYPE>::List()
{
firstPtr = lastPtr = 0;
}
//////////////////////////////////
template <class NTYPE>
List<NTYPE>::~List()
{
if (!isEmpty())
{
ListNode<NTYPE> *currentPtr = firstPtr, *tempPtr;
while(currentPtr != 0)
{
tempPtr = currentPtr;
cout<<currentPtr->data<<" udalyyaetsya iz spiska"<<endl;;
currentPtr = currentPtr->nextPtr;
delete tempPtr;
}
}
cout<<"Vse uzly udaleny"<<endl;
}
/////////////////////////////////
template <class NTYPE>
void List<NTYPE>::insertAtFront(const NTYPE &value)
{
ListNode<NTYPE> *newPtr = getNewNode(value);
if (isEmpty())
firstPtr = lastPtr = newPtr;
else
{
newPtr->nextPtr = firstPtr;
firstPtr = newPtr;
}
}
//////////////////////////////////////////////////
template <class NTYPE>
void List<NTYPE>::insertAtBack(const NTYPE &value)
{
ListNode<NTYPE> *newPtr = getNewNode(value);
if (isEmpty())
firstPtr = lastPtr = newPtr;
else
{
lastPtr->nextPtr = newPtr;
lastPtr = newPtr;
}
}
///////////////////////////////////
template <class NTYPE>
int List<NTYPE>::isEmpty()
{
return firstPtr == 0;
}
///////////////////////////////////////
template <class NTYPE>
ListNode<NTYPE> * List<NTYPE>::getNewNode(const NTYPE &value)
{
ListNode<NTYPE> *ptr = new ListNode<NTYPE>(value);
assert (ptr != 0);
return ptr;
}
////////////////////////////////////
template <class NTYPE>
void List<NTYPE>::print()
{
if (isEmpty())
{
cout<<"Spisok pust"<<endl<<endl;
return;
}
ListNode<NTYPE> *currentPtr = firstPtr;
cout<<"Spisok sostoit iz: ";
while(currentPtr != 0)
{
cout<<currentPtr->data<<' ';
currentPtr = currentPtr->nextPtr;
}
cout<<endl;
}
#include <iostream>
using namespace std;
void main()
{
List<int> intList;
intList.insertAtBack(5);
intList.insertAtBack(9);
intList.insertAtBack(0);
intList.print();
List<char *> strList;
strList.insertAtBack("template");
strList.insertAtBack("<class");
strList.insertAtBack("char*>");
strList.print();
system("pause");
}
А я хочу сделать, чтобы нужно было вводить имя типа с клавиатуры, а после в зависимости от полученного типа создавался соответствующий узел списка, что-то вроде
....................
cin>>nameOfType; //"int"
................
if (strcmp(nameOfType, "int") == 0)
{
ListNode<int> intNode(0);
}
else if.......................
...............
Только не могу реализовать, так как класс ListNode должен иметь тот же тип что и List, а для моего случая наверно нужно класс List без шаблонов делать. Также непонятно как указатель от ListNode<int> сможет указывать на ListNode<char*>. Функция print врядли сможет с помощью указателей пробежаться по списку. Может есть другой способ решения?
С этим указателем точно врядли получится, даже на примере функции добавления нового элемента
void List<NTYPE>::insertAtFront(const NTYPE &value)
{
void* newPtr = getNewNode(value); //сделаю указателем на любой тип
if (isEmpty())
firstPtr = lastPtr = newPtr;
else
{
newPtr->nextPtr = firstPtr;
firstPtr = newPtr;
}
}
Строчка newPtr->nextPtr = firstPtr; не сможет выполниться, так как в указателе на void не предусмотрены внутренние данные.
Было бы хорошо для базовых типов, но вот только union нигде не использовал, кроме битового представления числа.
Строчка newPtr->nextPtr = firstPtr; не сможет выполниться, так как в указателе на void не предусмотрены внутренние данные.
не знаю как ты манипулируешь что у тебя в итоге void хранит значение следующего звена,
например лист с СТЛ смотри
#include <list>
using namespace std;
main()
{
list<void*> Lvoid;
char *Cptr = new char[6];
strcpy(Cptr,"Hello");
void *somePtr = (void*)Cptr;
Lvoid.push_back((void*)new int(4));
Lvoid.push_back((void*)Cptr);
cout << *((int*)*Lvoid.begin()) << endl;
cout << (char*)*--Lvoid.end();
cin.get();
}
вобщем я бы посоветовал сделать структуру или класс с такими элементами:
struct SomeClass {
void *ptr;
Types type;
};
class List{
public:
//some method
private:
SomeClass value;
SomeClass *next;
SomeClass *prev;
};
вот и у тебя класс лист хранит уже ссылки на следующий и предыдущий элементы
Проблема что не работают массивы, невозможно переходить на следующий элемент.
Только вот мне кажется что шаблоны как раз и должны заменять указатель на void, ведь так программу я мог бы написать и на языке С.
И ещё эти 2 записи я не понял:
*((int*)*Lvoid.begin()) //Зачем * перед LVoid?
(char*)*--Lvoid.end() //Та же непонятная * и ещё --, хотя у меня эти унарные операции ++ и -- не работали.
И ещё эти 2 записи я не понял:
*((int*)*Lvoid.begin()) //Зачем * перед LVoid?
(char*)*--Lvoid.end() //Та же непонятная * и ещё --, хотя у меня эти унарные операции ++ и -- не работали.
Шаблоны в С++ нужны для описания поведения однотипных объектов. А у тебя не однотипные получаются и задача не тривиальная.
*((int*)*Lvoid.begin()) // Lvoid.begin() возвращает итератор первого элемента списка (итератор в данном случае похож на указатель, в котором хранится значение типа void*). Для того чтобы достать void* необходимо разыменовать итератор.
(char*)*--Lvoid.end() // Lvoid.end() возвращает итератор следующий за последним элементом листа, поэтому перед его использованием необходимо префиксный инкремент использовать и также разыменовываем чтоб получить void* с итератора