Шаблонные классы и базовые классы?

У меня есть базовый класс IStructure, который является производным от многих классов.

Некоторые из этих классов ссылаются на другие IStructure классы. Например, мой класс class GuiButton : public IStructure имеет член Textstring (который также является производным от IStructure).

Сейчас я просто мелькаю, чтобы перейти к сути, так что некоторым из вас это может показаться странным. Я хотел бы иметь класс шаблона «Ссылка», который ссылается на IStructure. Например:

class GuiButton : public IStructure {
public:
    Reference<Textstring> Text;
};

Я знаю, что некоторые из вас могут задаться вопросом, почему я просто не делаю Textstring* Text. Это связано с тем, что некоторые из этих ссылок являются «внешними». Класс шаблона Reference содержит только информацию о IStructure (т.е. имя и т. д.). Некоторые из этих классов безумно велики, и было бы бессмысленно создавать экземпляр всего класса только для использования свойства Name, а что нет. Имеет ли это смысл?

Итак, теперь к моему вопросу:

class Textstring : public IStructure;

Я могу сослаться на Textstring, используя свой шаблон:

Reference<Textstring> Text;

Теперь вот проблема: некоторые методы, которые у меня есть, требуют, чтобы я выполнял преобразование в IStructure, например:

void RegisterReference(Reference<IStructure> &reference);

Поэтому я не мог сделать это:

Reference<Textstring> txt("TextName");
RegisterReference(txt); // error

Я знаю, что могу вылечить это, если Reference не будет шаблоном, но мне бы очень хотелось, потому что это облегчает понимание и знание типа ссылки.

Какими способами я могу это сделать?

Спасибо за вашу помощь!

-Алекс


person Noah Roth    schedule 01.09.2012    source источник
comment
Может ли RegisterReference быть шаблонным? как в шаблоне‹typename T› void RegisterReference(Reference‹T› &reference);   -  person walrii    schedule 01.09.2012


Ответы (2)


Вы можете сделать свою функцию шаблоном для параметра типа Reference, например:

template <typename R>
void RegisterReference(Reference<R> &r);
person Sergey Kalinichenko    schedule 01.09.2012
comment
Хорошо, я попробовал template<class TIStructure> void addReference(void* resolvePoint, Reference<TIStructure> referenced, unsigned int fileType);, но выдает ошибку syntax error: identifier 'Reference'. Не уверен, что я делаю неправильно... - person Noah Roth; 01.09.2012
comment
Доступно ли определение класса шаблона Reference в том месте, где вы объявляете addReference? - person Sergey Kalinichenko; 01.09.2012
comment
Эк - может быть! Спасибо. - person Noah Roth; 01.09.2012

Как подсказывает @dasblinkenlight, вы можете использовать шаблоны для своих библиотечных функций. Или вы можете добавить некоторую «дисперсию» к классу Reference:

template<typename T>
class Reference
{
    // ...
public:
    template<typename U>
    Reference(Reference<U> const & r) {
        // "copy" r into *this
    }
};

Или с операторами преобразования

template<typename T>
class Reference
{
    // ...
public:
    template<typename U>
    operator Reference<U>() {
        // convert Reference<T> into Reference<U>
    }
};

Недостатком этого подхода является то, что вы фактически создаете новые объекты каждый раз, когда вам нужно выполнить преобразование.

Редактировать

Спасибо Люку Дантону за указание на это. Код, который я написал, обрабатывает гораздо больше, чем восходящие преобразования. Он будет делать любые доступные преобразования. Чтобы немного ограничить вещи, мы могли бы сделать что-то вроде этого (в C++11):

template<typename T>
class Reference
{
    // ...
public:
    template<typename U,
      typename = typename std::enable_if<std::is_base_of<T, U>::value>::type>
    Reference(Reference<U> const & r) {
        // "copy" r into *this
    }
};
person Ken Wayne VanderLinde    schedule 01.09.2012
comment
@walrii: Нет, это ответ @dasblinkenlight. Мой занимается только изменением самого класса Reference с помощью операторов преобразования и конструкторов. - person Ken Wayne VanderLinde; 01.09.2012
comment
Справедливости ради, я не думаю, что есть что-то неправильное в ограничении std::is_convertible, которое включает производное в базовое. Суть в том, чтобы вообще избегать ограничений: это сделало бы Reference<char*> конвертируемым в Reference<int> или всякую ерунду. - person Luc Danton; 01.09.2012