Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Повторное использования кода


Автор: VictorOff 19.1.2012, 12:01
Уважаемые знатоки! 
Требуется ваш совет в области повторного использования кода.
Имеется класс небинарного дерева и класс его узлов. (Пусть будет TBaseTree и TBaseTreeNode) Там реализован весь функционал относящийся к деревьям (построение, поиск, и т.д.)
Теперь у меня есть класс с дополнительным функционалом (пусть будет TMyTree и TMyTreeNode). Как быть? Если я унаследую его от TBaseTree, то все его функции типа Childs, Find и т.д. возвращают TBaseTreeNode. 
Код

TBaseTreeNode * __fastcall TBaseTreeNode::Childs()

и мне придется всюду использовать приведение к TMyTreeNode, что неудобно. 
Перебрав различные варианты (в том числе и субклассирование) я остановился на следующем:
В качестве базового класса использую шаблонный класс 
Код

template <class T> class TBaseTreeNode

а параметр T использую для получения значений в функциях типа Childs 
Код

template <class T> T* __fastcall TMyTreeNode <T>::Childs()

TMyTreeNode наследую от TBaseTreeNode с передачей в параметр своего класса
Код

class TMyTreeNode: public TBaseTreeNode < TMyTreeNode >

Выбранный вариант устраивал до тех пор, пока не понадобился интерфейс класса TBaseTree.
(это надо чтоб в определенном модуле программы объявить переменную с типом абстрактного интерфейса IBaseTree, а передавать в него объекты различных вариантов реализации TMyTreeNode1, TMyTreeNode2…)
При работе с параметризированным классом TBaseTree это невозможно. Был бы очень благодарен, если кто-нибудь поделился дельным советом. 

Автор: xvr 19.1.2012, 13:46
Цитата(VictorOff @  19.1.2012,  12:01 Найти цитируемый пост)
Выбранный вариант устраивал до тех пор, пока не понадобился интерфейс класса TBaseTree.
(это надо чтоб в определенном модуле программы объявить переменную с типом абстрактного интерфейса IBaseTree, а передавать в него объекты различных вариантов реализации TMyTreeNode1, TMyTreeNode2…)

А как вы потом разберетесь какая именно реализация к вам пришла?

Цитата(VictorOff @  19.1.2012,  12:01 Найти цитируемый пост)
При работе с параметризированным классом TBaseTree это невозможно.

Делаете интерфейс IBaseTree, и наследуете шаблонный класс TBaseTree от него. Таким образом IBaseTree (не шаблонный) станет родителем всех шаблонных производных от TBaseTree (что вам собственно и надо)

Автор: VictorOff 19.1.2012, 14:37
Цитата

Делаете интерфейс IBaseTree, и наследуете шаблонный класс TBaseTree от него. Таким образом IBaseTree (не шаблонный) станет родителем всех шаблонных производных от TBaseTree (что вам собственно и надо)


А можно поконкретнее?
Ранее у меня было
Код

template<class T> class TBaseNode
{
public:
    virtual T* __fastcall FirstChild() {return NULL;}
};
//---------------------------------------------------------------------------

class TMyNode : public TBaseNode<TMyNode>
{
public:
    void __fastcall MyFunction() {;}
};

TMyNode *MyNode;
...
TMyNode *MyChildNode=MyNode->FirstChild();
MyChildNode->MyFunction();

хотелось бы иметь возможность что-то вроде
Код

class IBaseNode
{
    virtual IBaseNode* __fastcall FirstChild()=0; //IBaseNode*?!
}; 
TMyNode *MyNode;
...
IBaseNode *BaseNode = MyNode;    

но как реализовать данный вариант? Это не работает.
Код

template<class T> class TBaseNode : public IBaseNode
{
public:
    virtual T* __fastcall FirstChild() {return NULL;}
};
//---------------------------------------------------------------------------

class TMyNode : public TBaseNode<TMyNode>
{
public:
    void __fastcall MyFunction() {;}
};


Следовательно, использование параметризированного класса TBaseNode не лучший вариант, если требуется работа с интерфейсом и необходима к.л. другая конструкция?

Автор: xvr 19.1.2012, 17:36
Цитата(VictorOff @  19.1.2012,  14:37 Найти цитируемый пост)
но как реализовать данный вариант? Это не работает.

Именно так. Почему не работает? В смысле не дает перегрузить FirstChild() ? Сделайте так:
Код

class IBaseNode
{
virtual IBaseNode* __fastcall real_FirstChild()=0;
};

template<class T> class TBaseNode : public IBaseNode
{
public:
virtual IBaseNode* __fastcall real_FirstChild() {return NULL;}
T* __fastcall FirstChild() {return real_FirstChild();}
};

class TMyNode : public TBaseNode<TMyNode>
{
public:
void __fastcall MyFunction() {;}
};


Автор: VictorOff 20.1.2012, 08:24
Цитата

Именно так.

Код

class IBaseNode
{
public:
    virtual IBaseNode* __fastcall real_FirstChild()=0;
};
//---------------------------------------------------------------------------

template<class T> class TBaseNode : public IBaseNode
{
public:
    virtual IBaseNode* __fastcall real_FirstChild() {return NULL;}
    T* __fastcall FirstChild() {return real_FirstChild();}
};
//---------------------------------------------------------------------------

class TMyNode : public TBaseNode<TMyNode>
{
public:
    void __fastcall MyFunction() {;}
};

Просто хотелось как-то поизящнее, если уж так, то можно сразу обойтись без шаблона
Код

class IBaseNode
{
public:
    virtual IBaseNode* __fastcall real_FirstChild()=0;
};
//---------------------------------------------------------------------------

class TBaseNode : public IBaseNode
{
public:
    virtual IBaseNode* __fastcall real_FirstChild() {return NULL;}
};
//---------------------------------------------------------------------------

class TMyNode : public TBaseNode
{
public:
    void __fastcall MyFunction() {;}
    virtual TMyNode* __fastcall FirstChild() {return static_cast<TMyNode*>(real_FirstChild());}
};

Немного не коробит, что при вызове через интерфейс необходимо использовать одно наименование метода, а в TMyNode другое?

Автор: xvr 20.1.2012, 12:07
Цитата(VictorOff @  20.1.2012,  08:24 Найти цитируемый пост)
Просто хотелось как-то поизящнее, если уж так, то можно сразу обойтись без шаблона

Так вам придется определять FirstChild в каждом конечном наследнике.

Цитата(VictorOff @  20.1.2012,  08:24 Найти цитируемый пост)
Немного не коробит, что при вызове через интерфейс необходимо использовать одно наименование метода, а в TMyNode другое? 

Увы, ваш IBaseNode слишком generic, что бы в нем можно было найти общий базовый класс для возврата из FirstChild(). У вас фактически каждый TBaseNode<> реализует свое дерево (по типу аргумента шаблона). И на уровне самого шаблона TBaseNode нет никакой связи между типом T и IBaseNode

Автор: VictorOff 20.1.2012, 13:01
xvr, согласен, вы правы, спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)