#c #oop #templates #inheritance #virtual
#c #ооп #шаблоны #наследование #виртуальный
Вопрос:
У меня есть класс контейнера шаблонов, который я производный от вызываемого MyContainer
. MyContainer
определяет такие методы, как Get()
, Set()
и т.д. для доступа к отдельным элементам. Я хотел бы создать класс bitfield, реализованный как MyContainer<char>
, где каждый char
элемент содержит CHAR_BIT
количество битов. Однако, чтобы позволить пользователю оперировать отдельными битами, а не целыми байтами, мне пришлось бы сделать Get()
и Set()
виртуальными, что незаконно. Каковы некоторые альтернативы?
Я думал определить GetBit()
и SetBit()
в производном классе, но это нарушило бы принцип подстановки Лискова. (Подумайте о SortMyContainer()
функции.)
РЕДАКТИРОВАТЬ: Вот упрощенный пример:
template <typename Datatype>
struct MyContainer
{
virtual Datatype Get();
};
template <typename Datatype> // Error: Templates may not be virtual.
virtual Datatype MyContainer<Datatype>::Get() // EDIT: The problem was on this line. The "virtual" keyword should only appear with the function declaration.
{
// ...
}
Комментарии:
1. Могу ли я рассказать вам о шаблоне NVI или методе шаблона? Смотрите gotw.ca/publications/mill18.htm . STL часто реализуется по этому принципу.
Ответ №1:
Это не является незаконным, только виртуальные функции-члены шаблона являются.
// valid
template<typename T> class MyContainer {
virtual void set(const T amp;) = 0;
}
// not valid
class MyContainer {
template <typename T> virtual void set (const T amp;) = 0;
}
Если я вас неправильно понял, пожалуйста, рассмотрите возможность размещения примера кода.
редактируйте после добавления вами примера кода:
template <typename Datatype>
virtual // <-- nope, not here
Datatype MyContainer<Datatype>::Get()
{
// ...
}
virtual
это только часть объявления внутри тела класса. Это должно быть допустимо:
template <typename Datatype>
Datatype MyContainer<Datatype>::Get()
{
// ...
}
Однако обратите внимание, что определение должно быть видимым в момент создания экземпляра шаблона. Так что либо поместите это также в заголовочный файл (или в дополнительный заголовок, который вы затем включаете в свой реальный заголовок), либо оставьте это в теле класса.
(пожалуйста, сейчас никто не упоминает export
шаблоны ed, мы с вами их хорошо знаем, но они не совсем для начинающих и устарели со следующим стандартом)
Комментарии:
1. Однако функции-члены являются шаблонами; они используют параметр шаблона класса в возвращаемых значениях и параметрах.
2. @Maxpm: Это не имеет значения. Если они сами по себе не имеют параметров шаблона, то они не являются шаблонами.
3. @phresnel @DeadMG Я добавил упрощенный пример в OP.
4. @Maxpm: Если ваш компилятор отклоняет этот код, значит, это неправильно . О, помимо того факта, что вы не должны помещать
virtual
туда.5. @DeadMG: Иногда компиляторы ошибаются, особенно очень устаревшие. @Maxpm: Как указывает DeadMG, при переопределении функций-членов virtual должно быть опущено. Это только часть объявления внутри тела класса.
Ответ №2:
Похоже, вы не понимаете, что представляет собой шаблон. Шаблоны классов могут иметь виртуальные функции, и действительно, эти параметры шаблона могут отображаться в сигнатурах этих функций.
template<typename T> class an_interface {
virtual T Get() = 0;
};
class a_class : public an_interface<int> {
};
Это совершенно справедливо. Что не совсем корректно, так это
class an_interface {
template<typename T> virtual T Get() = 0;
}
Если конкретная функция-член, о которой идет речь, не имеет собственных, отдельных параметров шаблона, функция-член не является шаблоном и может быть виртуальной, независимо от того, была ли она сгенерирована из шаблона класса.