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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> template Tree list что не так? Судите строго :) 
:(
    Опции темы
azesmcar
Дата 22.2.2006, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


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

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



Здравствуйте...есть класс Tree, для добавления веток, удаления...поиска и всего остального (некоторые функции убраны из класса...что-то мне здесь не нравится...не могу сказать что, просто смотрю на код и чувствую что что-то не то...

Может я слишком самокритичен? smile

Кому не лень помогите подправить...что в коде не то? что надо добавить, убрать...неэлегантно как-то...вобщем на ваше усмотрение...у кого какие мысли по поводу класса...

Код

#ifndef __CTREE_H__
#define __CTREE_H__

#include <vector>
#include <algorithm>

template <class T>
class CTreeNode
{
public:
    /************************************************************************/
    typedef std::vector< CTreeNode<T>* >            Childs;
    typedef std::vector< CTreeNode<T>* >::iterator  ChildsIterator;

    /************************************************************************/
    CTreeNode()
        :m_pParent( 0 )
    {
    }
    /************************************************************************/
    CTreeNode( CTreeNode<T>* pParent, const T& Object )
        :m_pParent( pParent ), m_Object( Object )
    {
    }
    /************************************************************************/
    ~CTreeNode()
    {
        for (std::vector< CTreeNode<T>* >::iterator it = m_Childs.begin(); it != m_Childs.end(); ++it)
        {
            delete (*it);
        }
    }
    /************************************************************************/
    int GetChildCount() const
    {
        return m_Childs.size();
    }
    /************************************************************************/
    void RemoveChild(ChildsIterator it)
    {
        delete (*it);
        m_Childs.erase( it );
    }
    /************************************************************************/
    void RemoveChild(const CTreeNode<T> *pNode)
    {
        std::vector< CTreeNode<T>* >::iterator it = std::find( m_Childs.begin(), m_Childs.end(), pNode );
        if ( it != m_Childs.end() )
        {
            m_Childs.erase( it );
            delete pNode;
        }
    }
    /************************************************************************/
    CTreeNode<T>* GetParent() const
    {
        return m_pParent;
    }
    /************************************************************************/
    CTreeNode<T>* AddChild(const T& Object)
    {
        m_Childs.push_back( new CTreeNode<T>( this, Object ) );
        return GetLastChild();
    }
    /************************************************************************/
    T& GetObject()
    {
        return m_Object;
    }
    /************************************************************************/
    void SetObject(const T& Object)
    {
        m_Object = Object;
    }
    /************************************************************************/
    ChildsIterator begin()
    {
        return m_Childs.begin();
    }
    /************************************************************************/
    ChildsIterator end()
    {
        return m_Childs.end();
    }
    /************************************************************************/
    CTreeNode<T>* GetFirstChild()
    {
        return m_Childs.front();
    }
    /************************************************************************/
    CTreeNode<T>* GetLastChild()
    {
        return m_Childs.back();
    }
    /************************************************************************/
protected:
    T               m_Object;
    CTreeNode<T>*   m_pParent;
    Childs          m_Childs;
};

template <class T>
class CTree
{
public:
    typedef CTreeNode<T>* TreeNodeType;
    /************************************************************************/
    CTreeNode<T>* GetRootNode()
    {
        return &m_pRootNode;
    }
    /************************************************************************/
protected:
private:
    CTreeNode<T> m_pRootNode;
};

#endif



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

#include "CTree.h"
#include <iostream>

void test_out(CTreeNode<std::string>* pTreeNode)
{
    for (CTreeNode<std::string>::ChildsIterator it = pTreeNode->begin(); it != pTreeNode->end(); ++it)
    {
        std::cout << (*it)->GetObject().c_str() << std::endl;
        test_out( (*it) );
    }
}

int main()
{
    CTree<std::string> t;
    CTree<std::string>::TreeNodeType node = 0;
    
    node = t.GetRootNode()->AddChild("ROOT1");
    
    node = node->AddChild("Child1");
    node->AddChild("SubChild1");
    node->AddChild("SubChild2");
    node->AddChild("SubChild3");
    node->AddChild("SubChild4");
    node->AddChild("SubChild5");

    test_out(t.GetRootNode());


Например мне не нравится то что пользователь класса задает в template тип std::string а итератор надо разименовывать чтобы получить...вобщем как то не стандартно...(сам написал, сам недоволен...куда катится этот мир smile )


Заранее спасибо...

Это сообщение отредактировал(а) azesmcar - 22.2.2006, 11:43
PM   Вверх
MAKCim
Дата 22.2.2006, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

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



Цитата

Например мне не нравится то что пользователь класса задает в template тип std::string

а что такого? Как еще контейнерами пользоваться? smile
Код

...
private:
    CTreeNode<T> m_pRootNode;
...

может лучше хранить указатель или типа smart_ptr<CTreeNode<T> >?
потому как вроде когда создается CTree появляется сразу первый CTreeNode, хотя вначале дерево не содержит узлов
(это мое ИМХО)
Код

 typedef CTreeNode<T>* TreeNodeType;
    /************************************************************************/
    CTreeNode<T>* GetRootNode()
    {
        return &m_pRootNode;
    }

опять же работа с указателем (передается во внешнюю ф-ию), что небезопасно, наверно лучше опять же использовать
какие-нибудь smart_ptr

может быть будет разумно вообще скрыть реализацию CTreeNode поместив этот шаблон класса в private секцию CTree
предоставив пользователю только итератор по CTree

удачи


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

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


uploading...
****


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

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



Цитата

а что такого? Как еще контейнерами пользоваться?


А продолжение?

Цитата

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


имеется ввиду к примеру если создать
Код

std::list<std::string> t;
t.begin() //итератор который если разименовать получим std::string


а в моем случае если его разименовать получим указатель а не сам обьект...
нестандартно...можно конечно добавлять статические обьекты но на мой взгляд это не очень-то хорошо...так как vector резервирует память, и чем больше размер обьекта, тем больше памяти он зарезервирует...потому лучше хранить указатели (на мой взгляд)...
Цитата

может лучше хранить указатель или типа smart_ptr<CTreeNode<T> >?

можно...подумаю над этим...вопрос спорный, в принципе дерево без RootNode смысла не имеет...можно просто создавать его при первом же обращении...

Цитата

может быть будет разумно вообще скрыть реализацию CTreeNode поместив этот шаблон класса в private секцию CTree
предоставив пользователю только итератор по CTree


в принципе пользователь не должен иметь возможности создавать обьект типа CTreeNode..тоже вариант..можно сделать конструктор и деструктор private и подружить классы...
PM   Вверх
Earnest
Дата 22.2.2006, 20:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



1) Я бы поменяла vector на list (для хранения детей). Основание: дерево воспринимается как динамическая структура, к-я погибче вектора. Как-то подсознательно ожидаешь, что итераторы будут оставаться валидными после любых операций (кроме удаления).

2) Не нравится разыменование - напиши свой итератор. Проще всего это сделать с помощью boost::iterator_adapter - всего одну функцию придется написать.

3) Согласна с MAKCim насчет скрывания TreeNode и написания итератора по всему дереву. Лучше, чтобы итератор разыменовывался в тип T, а не в TreeNode. Здесь тоже рулит iterator_adapter.

4)
Цитата(azesmcar @ 22.2.2006, 11:37 Найти цитируемый пост)
Например мне не нравится то что пользователь класса задает в template тип std::string

Это нормально. Просто "правильные" пользователи сачала напишут
Код

typedef CTree<string> CStringTree;

И все будет красиво.

Еще раз повторюсь, итератор-адаптер для твоего случая очень подходит, рекомендую ознакомиться.



--------------------
...
PM   Вверх
MAKCim
Дата 22.2.2006, 20:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

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



Цитата

в принципе пользователь не должен иметь возможности создавать обьект типа CTreeNode..тоже вариант..можно сделать конструктор и деструктор private и подружить классы...

только не дружба! smile , лучше поместить в protected секцию
Цитата

имеется ввиду к примеру если создать
Код

std::list<std::string> t;
t.begin() //итератор который если разименовать получим std::string

а в моем случае если его разименовать получим указатель а не сам обьект...
нестандартно...можно конечно добавлять статические обьекты но на мой взгляд это не очень-то хорошо...так как vector резервирует память, и чем больше размер обьекта, тем больше памяти он зарезервирует...потому лучше хранить указатели (на мой взгляд)...

можно хранить указатели но можно создать свой итератор (точнее обертку над std::vector< CTreeNode<T>* >::iterator)
Код

template<class T> class CIterator
{
private:
    typedef typename std::vector<CTreeNode<T>*>::iterator iterator;
    iterator iter;
public:
    CIterator(iterator i): iter(i) {}
    CTreeNode<T>& operator*() {return *(*iter);}
    const CTreeNode<T>& operator*() const {return *(*iter);}
    void operator++(int p) {iter++;}
    void operator++() {++iter;}
    ...
};

//где-то в CTreeNode

...
typedef CIterator<T> ChildsIterator;
...
    ChildsIterator begin()
    {
        return m_Childs.begin();
    }
    /************************************************************************/
    ChildsIterator end()
    {
        return m_Childs.end();
    }



--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

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


uploading...
****


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

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



Цитата

Согласна с MAKCim насчет скрывания TreeNode и написания итератора по всему дереву.


Все больше склоняюсь к этому решению...к сожалению boost -а нету...и инсталировать его тоже никто в нашей фирме (пока что) не собирается..можно посмотреть как реализовано или скопировать...

Но возникают некоторые вопросы...тогда надо будет убрать все что написано и изменить структуру...
т.е. будут функции
Код

insert_after(iterator it, const T& object);
insert_under(iterator it, const T& object);
...


И тому подобное..но как тогда получить из итератора parent если вся имплементация CTreeNode будет скрыта от пользователя...нужно к примеру пройтись по child -ам конкретного node -а...но не рекурсивно...а обычно, только для immediate-childs..проверить есть ли у какой либо ветки дети для функции (is_leaf)...и множество других воросов..как же быть с ними?
PM   Вверх
Daevaorn
Дата 23.2.2006, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 51
Всего: 70



Цитата(azesmcar @ 23.2.2006, 12:15 Найти цитируемый пост)
И тому подобное..но как тогда получить из итератора parent если вся имплементация CTreeNode будет скрыта от пользователя...нужно к примеру пройтись по child -ам конкретного node -а...но не рекурсивно...а обычно, только для immediate-childs..проверить есть ли у какой либо ветки дети для функции (is_leaf)...и множество других воросов..как же быть с ними?

Это всё не задача итератора. Он должен только осуществлять обход (operator++() и прочие). А все датали реализации это уже дело Node, а значит его совсем от клиентского кода скрывать не следует
PM MAIL WWW   Вверх
azesmcar
Дата 23.2.2006, 11:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


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

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



Цитата

Это всё не задача итератора. Он должен только осуществлять обход (operator++() и прочие). А все датали реализации это уже дело Node, а значит его совсем от клиентского кода скрывать не следует


Ну...так и я об этом smile думаю можно переименовать iterator на node_iterator чтобы пользователю класса было понятно что итерация у него будет по node -ам..а не по обьектам...а уж потом
Код

node->GetObject();
node->AddChild(...);
node->GetParent()->GetChildCount();


получай обьект в свое удовольствие...добавляй child-ы...получай любую информацию...если скрыть node все это будет недуступно..какой же тогда смысл строить дерево?
PM   Вверх
Daevaorn
Дата 23.2.2006, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 51
Всего: 70



Цитата(azesmcar @ 23.2.2006, 12:39 Найти цитируемый пост)
какой же тогда смысл строить дерево?

Ну на самом деле класс дерева нужен чтобы хранить root smile Конечно, он ещё size()( самый лучший вариант это кешировать размер, так делает STL ) должен возвращать и сервисные операции: вставка, удаление, поиск и т.д. На Node эти операции лучше не вешать.
PM MAIL WWW   Вверх
MAKCim
Дата 23.2.2006, 18:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

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



Цитата

Ну...так и я об этом думаю можно переименовать iterator на node_iterator чтобы пользователю класса было понятно что итерация у него будет по node -ам..а не по обьектам...а уж потом
Код

node->GetObject();
node->AddChild(...);
node->GetParent()->GetChildCount();

получай обьект в свое удовольствие...добавляй child-ы...получай любую информацию...если скрыть node все это будет недуступно..какой же тогда смысл строить дерево?

все равно раскрывается реализация Node, что не есть хорошо
можно создать псевдо Node с одним открытым методом - получение итератора на первый из child-ов, объект которого возвращает итератор (можно создать разновидности итератора для прохода дерева в прямом, обратном, ... порядке) tree, в конечном итоге важен ведь не Node, а значение в нем


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

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

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


 




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


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

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