Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / LECS17.DOC
Скачиваний:
44
Добавлен:
16.04.2013
Размер:
151.55 Кб
Скачать

В файле gentree2.H

//Обобщенные деревья двоичного поиска

typedef void* p_gen; //тип обобщенного показателя

int comp (p_gen a, p_gen b);

class bnode { //узел

private:

friend class gen_tree;

bnod* left;

bnod* right;

p_gen data;

int count;

bnod(p_gen d, bnod* l, bnod* r) :

data(d), left(l), right(r), count (1) {}

friend void print(bnod* n);

};

class gen_tree { //дерево

public:

gen_tree() { root = 0; }

void insert(p_gen d);

p_gen find(p_gen d) const { return (find(root, d)); }

void print () const { print(root); }

protected:

bnode* root; //корень

p_gen find(bnode*r, p_gen d) const;

void print(bnode*r) const;

};

Отдельные узлы в этом двоичном дереве хранят обобщенный указатель data и целую count, которая будет подсчитывать повторяющиеся вхождения. Указатель data будет соответствовать типу указателя в производном классе. Дерево будет представлять собой дерево двоичного поиска, в котором узлы с меньшем значением будут храниться слева, а с большим значением – слева. Нам нужен способ для сравнения значений, подходящий для конкретного производного типа. Мы используем дружественную функцию comp(), которая является другом bnode и будет написана надлежащим образом для производного класса.

Функция insert() помещает узлы в дерево; она должна находить в дереве позицию для очередного узла.

void gen_tree::insert(p_gen d)

{

bnode* temp = root;

bnode* old;

//template<class T> void gen_tree<T>::insert(T>::insert(T d)

}

Функция p_gen find(bnode*r, p_gen d) ищет в поддереве к корнем r информацию, представленную d.

p_gen gen_tree::find(bnode*r, p_gen d) const

{

...

}

Функция print() - это стандартная рекурсия. В каждом узле применяется внешняя функция ::print().

void gen_tree:: print(bnod* r) const

{

if (r != 0) {

print(r ->left);

::print r;

print(r ->right);

}

}

Теперь создадим производный класс, который в качестве членов данных сможет хранить указатели на char.

В файле gentree2.Cpp

#include "gentree2.h"

#include <cstring> //для старых систем: string.h

using namespace std;

class s_tree : privat gen_tree { //дерево строк

public:

s_tree() {}

void insert (char* d) { gen_tree::insert(d); }

char* find(char* d) const

{ return static_cast< char*>(gen_tree::find(d));}

void print() const { gen_tree:: print(); }

};

Функция вставки gen_tree::insert из базового класса принимает в качестве аргумента обобщенный указатель. Функция вставки s_tree::insert производного класса принимает в качестве аргумента указатель на char. Таким образом, в производном классе s_tree функция

void insert (char* d) { gen_tree::insert(d); }

использует неявное преобразование сhar* k void*.

Нам нужна функция, выполняющая сравнение:

int comp(p_gen i, p_gen j)

{

return (strcmp(static_cast<char*>(j) );

}

Кроме того, нужна внешняя функция print() для рекурсивного использования s_tree::print() в выводящей дерево целиком; она должна уметь правильно печатать значения, хранящиеся в отдельном узле.

void print(bnode* n)

{

cout << static_cast<char*>(n -> data) <<’\t’;

cout << n -> count << ‘\t’;

}

Заметьте, что там, где соответствующий шаблонный код использовал шаблонный параметр, в этой версии программы для gen_tree применяется тип обобщенного указателя p_gen.

Методика шаблонов проще и более эффективна на этапе выполнения. Она проще, потому что для инстанцирования необходим единственный фактический тип, помещаемый в объявление шаблона. При наследовании же необходимо наследовать весь интерфейс, подставляя надлежащие типы. Методика шаблонов более эффективна на этапе выполнения, потому что часто можно избежать ненужных «косвенностей». С другой стороны, наследование позволяет, если необходимо, разработать специфический код для каждого типа. Наследование не приводит к большим модулям объектного кода. Помните, что каждое инстанцирование шаблона компилируется в объектный код.

Соседние файлы в папке Лекции