Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Класс List c поддержкой произвольных типов, как реализовать? 
V
    Опции темы
zim22
Дата 26.5.2009, 15:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Необходимо было реализовать список, который может хранить элементы трёх разных типов: int, double, string.
С помощью селектора типов я реализовал задачу.
Но моё решение мне не нравится, по нескольким причинам:
1) избыточность данных. Т.к. данные я храню в классе DataType и реально используется только один тип данных.
2) в дальнейшем может понадобиться добавить новые типы для хранения, например vector<string>, Complex, Shape. И мне необходимо будет модифицировать классы...
Что вы можете предложить? Расширения типа boost не предлагать. Должно быть на чистом С++.

List.h
Код

#ifndef LIST_H
#define LIST_H

#include <string>
#include <iostream>

class DataType {
public:  
  friend std::ostream &operator<<(std::ostream &out, const DataType &obj) {
    switch (obj.type) {
      case INT: out << obj.ival; break;
      case DOUBLE: out << obj.dval; break;
      case STRING: out << obj.sval; break;
      default: std::cerr << "Type is illegal"; break;
    }
    return out;
  }
  DataType(int i) : type(INT), ival(i) { }
  DataType(double d) : type(DOUBLE), dval(d) { }
  DataType(const std::string &s) : type(STRING), sval(s) { }
  DataType(char *s) : type(STRING), sval(s) { }
private:
  enum eType {INT, DOUBLE, STRING};
  eType type;
  int ival;
  double dval;
  std::string sval;
};

class List {
public:    
  List() : head(0), current(0) { }  
  void push(DataType d) {
    if (head == 0)
      current = head = new ListItem(d);
    else
      current = current->next = new ListItem(d);
  }
  void print() {
    for (ListItem *p = head; p; p = p->next)
      std::cout << p->value << std::endl;
  }
private:
  struct ListItem {    
    ListItem(DataType val, ListItem *n = 0) : value(val), next(n) { }
    DataType value;
    ListItem *next;
  };
  ListItem *head, *current;
};

#endif // LIST_H


main.cpp
Код

List l;
l.push(10);
l.push(22.33);
l.push("hello");
l.print();

// потенциальные типы на добавление в список
std::vector<std::string> vs;
l.push(vs);

Complex c;
l.push(c);

Shape s;
l.push(s);



--------------------
PM MAIL   Вверх
azesmcar
Дата 26.5.2009, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата(zim22 @  26.5.2009,  15:09 Найти цитируемый пост)
Расширения типа boost не предлагать. 

а самому почему бы не реализовать any?

PM   Вверх
math64
Дата 26.5.2009, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



Код

class Data {
public:
virtual ~Data();
virtual print(ostream&os) const = 0;
};
ostream& operator << (ostream&os, const Data& d) { d.print(os); return os; }
class IntData : public Data {
int value;
public:
IntData(int v) : value(v) {}
virtual print(ostream&os) const;
};
class DoubleData : public Data {
double value;
public:
DoubleData(double v) : value(v) {}
virtual print(ostream&os) const;
};
class StringData : public Data {
string value;
public:
StringData(string v) : value(v) {}
virtual print(ostream&os) const;
};

class List {
public:    
  List() : head(0), current(0) { }  
  void push(Data& d) {
    if (head == 0)
      current = head = new ListItem(d);
    else
      current = current->next = new ListItem(d);
  }
  void print() {
    for (ListItem *p = head; p; p = p->next)
      std::cout << *(p->value) << std::endl;
  }
private:
  struct ListItem {    
    ListItem(Data& val, ListItem *n = 0) : value(&val), next(n) { }
   ~ListItem() { delete value; }
    Data* value;
    ListItem *next;
  };
  ListItem *head, *current;
};

PM   Вверх
zim22
Дата 26.5.2009, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



Цитата(azesmcar @  26.5.2009,  15:22 Найти цитируемый пост)
а самому почему бы не реализовать any?

мой опыт общения с boost - исползьование shared_ptr smile
я думал, что может быть просто есть архитектура или паттерн, который позволяет решить мою задачу более элегантно, чем это сделал я.

math64, спасибо, это почти то, что надо.
Однако сейчас список заполняется так:
Код

List l;
IntData id(10);
DoubleData dd(22.33);
StringData sd("hello");

l.push(id);
l.push(dd);
l.push(sd);


Как сделать, чтобы заполнение было прозрачно для пользователя?
Код

List l;
l.push(10); // IntData
l.push(22.33); // DoubleData
l.push("c++"); // StringData


Я перегрузил функцию push в классе List,
Код

class List {
public:    
...
void push(IntData i) {
    system_push(i); 
  }
  void push(DoubleData d) {
    system_push(d); 
  }
  void push(StringData s) {
    system_push(s);
  }
private:
void system_push(Data& d) {
    if (head == 0)
      current = head = new ListItem(d);
    else
      current = current->next = new ListItem(d);
  }


но всё-равно необходимо явно указывать тип объекта,
Код

l.push(IntData(10));
l.push(DoubleData(22.33));
l.push(StringData("c++"));

 иначе компилятор ругается
Цитата

error C2668: 'List::push' : ambiguous call to overloaded function
1>        list.h(48): could be 'void List::push(DoubleData)'
1>        list.h(45): or       'void List::push(IntData)'




Это сообщение отредактировал(а) zim22 - 26.5.2009, 15:48


--------------------
PM MAIL   Вверх
azesmcar
Дата 26.5.2009, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата(zim22 @  26.5.2009,  15:46 Найти цитируемый пост)
мой опыт общения с boost - исползьование shared_ptr smile
я думал, что может быть просто есть архитектура или паттерн, который позволяет решить мою задачу более элегантно, чем это сделал я.

а я о чем? написать что нибудь вроде boost::any

Код

template <class To, class From>
class TypeConverter
{
public:
    static To Convert(const From& from) {
        std::stringstream stream;
        stream << from;
        To value;

        //Check if stream is bad
        if ( stream.bad() )
        {
            throw std::bad_exception();
        }

        //Check if stream contains variable of type that you want to get
        if ((stream >> value).fail() || !stream.eof())
        {
            throw std::bad_cast();
        }

        return value;
    }
};

Код

template <class T, class U>
T lexical_cast(const U& from) {
    return TypeConverter<T, U>::Convert( from );
}

Код

class Any
{
public:
    template <class U>
    Any(const U& r) : value_( lexical_cast<std::string>( r ) ) {
    }

    Any(const Any& r) : value_( r.value_ ) {
    }

    template <class U>
    operator U() const {
        return lexical_cast<U>( value_ );
    }

    template <class U>
    Any& operator = (const U& r) {
        value_ = lexical_cast<std::string>( r );
        return *this;
    }

    bool operator == (Any& r) const {
        return ( value_ == r.value_ );
    }

    bool operator != (Any& r) const {
        return ( value_ != r.value_ );
    }

    bool operator > (Any& r) const {
        return ( value_ > r.value_ );
    }

    bool operator < (Any& r) const {
        return ( value_ < r.value_ );
    }

    bool operator >= (Any& r) const {
        return ( value_ >= r.value_ );
    }

    bool operator <= (Any& r) const {
        return ( value_ <= r.value_ );
    }
private:
    std::string value_;
};

и использование
Код

std::list<Any> t;
t.push_back(5);
t.push_back(7.8);
t.push_back("str1");


далее TypeConverter можно специализировать для любых не POD типов.

Это сообщение отредактировал(а) azesmcar - 26.5.2009, 15:58
PM   Вверх
zim22
Дата 26.5.2009, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 29
Всего: 69



azesmcar, то, что надо!  smile 


--------------------
PM MAIL   Вверх
math64
Дата 27.5.2009, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 12
Всего: 72



В примере azesmcar объекты будут храниться в списке уже в виде строк. Но можно конвертировать и в Data* 
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0736 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.