Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Связной список с разными типами данных

10K
31 октября 2007 года
Omega Red
49 / / 15.10.2006
Нужно создать связной список, в котором могут находиться данные разных типов, к примеру 5, 6.3, 'c', "abcd", 99. Я сделал только стандартный случай с однотипными данными. Выложу для примера:
Код:
//listnd.h
#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;
}


Код:
//list.h
#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 "list.h"
#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");
}



А я хочу сделать, чтобы нужно было вводить имя типа с клавиатуры, а после в зависимости от полученного типа создавался соответствующий узел списка, что-то вроде
 
Код:
char *nameOfType;
....................
cin>>nameOfType; //"int"
................
if (strcmp(nameOfType, "int") == 0)
    {
        ListNode<int> intNode(0);
    }
else if.......................
...............



Только не могу реализовать, так как класс ListNode должен иметь тот же тип что и List, а для моего случая наверно нужно класс List без шаблонов делать. Также непонятно как указатель от ListNode<int> сможет указывать на ListNode<char*>. Функция print врядли сможет с помощью указателей пробежаться по списку. Может есть другой способ решения?
14K
01 ноября 2007 года
stimpi
100 / / 04.09.2007
я могу и ошибаться, но думаю что ты должен отталкиваться от списка указателей типа void*, в С++ любой указатель можно привести к void* и наоборот при знании типа хранимых данных. Аналог на Java class Object.
276
01 ноября 2007 года
Rebbit
1.1K / / 01.08.2005
А еще можно union заюзать если только базовые типы надо.
10K
01 ноября 2007 года
Omega Red
49 / / 15.10.2006
Цитата:
я могу и ошибаться, но думаю что ты должен отталкиваться от списка указателей типа void*, в С++ любой указатель можно привести к void* и наоборот при знании типа хранимых данных. Аналог на Java class Object.


С этим указателем точно врядли получится, даже на примере функции добавления нового элемента

Код:
template <class NTYPE>
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 заюзать если только базовые типы надо.


Было бы хорошо для базовых типов, но вот только union нигде не использовал, кроме битового представления числа.

14K
01 ноября 2007 года
stimpi
100 / / 04.09.2007
Цитата: Omega Red
С этим указателем точно врядли получится, даже на примере функции добавления нового элемента

Строчка newPtr->nextPtr = firstPtr; не сможет выполниться, так как в указателе на void не предусмотрены внутренние данные.



не знаю как ты манипулируешь что у тебя в итоге void хранит значение следующего звена,

например лист с СТЛ смотри

Код:
#include <iostream>
#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();
}
хранит любой тип данных и извлекать можно зная что именно хранит.

вобщем я бы посоветовал сделать структуру или класс с такими элементами:
Код:
enum Types {char, char*, int, MyClass, ....., etc.};

struct SomeClass {
void *ptr;
Types type;
};

class List{
public:
//some method
private:
SomeClass value;
SomeClass *next;
SomeClass *prev;
};


вот и у тебя класс лист хранит уже ссылки на следующий и предыдущий элементы
10K
02 ноября 2007 года
Omega Red
49 / / 15.10.2006
Под указатели исправил, теперь работает. Делал немного не так, как в этом примере, у меня глобальная переменная типа Type, которой в мэйне присваиваю различные значения, а функция принт с помощью оператора switch приводит указатель к соответствующему значению.
Проблема что не работают массивы, невозможно переходить на следующий элемент.

Только вот мне кажется что шаблоны как раз и должны заменять указатель на void, ведь так программу я мог бы написать и на языке С.

И ещё эти 2 записи я не понял:
*((int*)*Lvoid.begin()) //Зачем * перед LVoid?
(char*)*--Lvoid.end() //Та же непонятная * и ещё --, хотя у меня эти унарные операции ++ и -- не работали.
14K
02 ноября 2007 года
stimpi
100 / / 04.09.2007
Цитата: Omega Red
Только вот мне кажется что шаблоны как раз и должны заменять указатель на void, ведь так программу я мог бы написать и на языке С.

И ещё эти 2 записи я не понял:
*((int*)*Lvoid.begin()) //Зачем * перед LVoid?
(char*)*--Lvoid.end() //Та же непонятная * и ещё --, хотя у меня эти унарные операции ++ и -- не работали.



Шаблоны в С++ нужны для описания поведения однотипных объектов. А у тебя не однотипные получаются и задача не тривиальная.
*((int*)*Lvoid.begin()) // Lvoid.begin() возвращает итератор первого элемента списка (итератор в данном случае похож на указатель, в котором хранится значение типа void*). Для того чтобы достать void* необходимо разыменовать итератор.
(char*)*--Lvoid.end() // Lvoid.end() возвращает итератор следующий за последним элементом листа, поэтому перед его использованием необходимо префиксный инкремент использовать и также разыменовываем чтоб получить void* с итератора

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог