Создание интерфейса для абстрактного класса обрабатывает по шаблону в C++

У меня есть код как ниже. У меня есть абстрактный шаблонный класс Foo и два подкласса (Foo1 и Foo2), которые происходят из инстанцирований шаблона. Я хочу использовать указатели в своей программе, которая может указать на любой на объекты типа Foo1 или Foo2, следовательно я создал интерфейс IFoo.

Моя проблема, я не уверен, как включать functionB в интерфейс, так как это - иждивенец на шаблонном инстанцировании. Даже возможно сделать functionB доступный через интерфейс, или я делаю попытку невозможного?

Большое спасибо за Вашу справку.

class IFoo {
    public:
        virtual functionA()=0;

};

template<class T>
class Foo : public IFoo{
    public:
        functionA(){ do something; };
        functionB(T arg){ do something; };
};

class Foo1 : public Foo<int>{
...
};

class Foo2 : public Foo<double>{
...
};
22
задан bishboshbash 15 July 2010 в 00:10
поделиться

4 ответа

Поскольку тип аргумента функцииВ должен быть известен заранее, у вас есть только один выбор: Сделать его типом, который может содержать все возможные аргументы. Это иногда называют "верхним типом", и в библиотеках boost есть тип any, который довольно близко подходит к тому, что мог бы делать верхний тип. Вот что могло бы работать:

#include <boost/any.hpp>
#include <iostream>
using namespace boost;

class IFoo {
    public:
    virtual void functionA()=0;
    virtual void functionB(any arg)=0; //<-can hold almost everything
};

template<class T>
class Foo : public IFoo{
    public:
        void functionA(){  };
        void real_functionB(T arg)
        {
         std::cout << arg << std::endl;
        };
        // call the real functionB with the actual value in arg
        // if there is no T in arg, an exception is thrown!

        virtual void functionB(any arg)
        {
            real_functionB(any_cast<T>(arg));
        }
};

int main()
{
    Foo<int> f_int;
    IFoo &if_int=f_int;

    if_int.functionB(10);

    Foo<double> f_double;
    IFoo &if_double=f_double;
if_int.functionB(10.0);

}

К сожалению, any_cast не знает об обычных преобразованиях. Например, any_cast(any(123)) выбрасывает исключение, потому что даже не пытается преобразовать целое число 123 в двойное. If не заботится о преобразованиях, потому что все равно невозможно воспроизвести их все. Таким образом, есть несколько ограничений, но при необходимости можно найти обходные пути.

4
ответ дан 29 November 2019 в 05:21
поделиться

Самый простой способ - создать интерфейс по шаблону.

template <class T>
class IFoo {
    public:
        virtual void functionA()=0;
        virtual void functionB(T arg){ do something; };
};

template<class T>
class Foo : public IFoo<T>{
    public:
        void functionA(){ do something; };
        void functionB(T arg){ do something; };
};
8
ответ дан 29 November 2019 в 05:21
поделиться

Вы действительно пытаетесь сделать невозможное.

Суть дела проста: виртуальный и шаблон плохо сочетаются друг с другом.

  • шаблон предназначен для генерации кода во время компиляции. Вы можете думать об этом как о макросах с распознаванием типов + несколько приколов для метапрограммирования.
  • virtual касается решения во время выполнения, и это требует некоторой работы.

virtual обычно реализуется с использованием виртуальных таблиц (подумайте о таблице, в которой перечислены методы). Количество методов должно быть известно во время компиляции и определяется в базовом классе.

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

А если бы это было возможно?

Ну, это просто не имело бы смысла. Что происходит, когда я вызываю Foo2 с int ? Это не предназначено для этого! Следовательно, это нарушает принцип, согласно которому Foo2 реализует все методы из IFoo .

Итак, было бы лучше, если бы вы указали реальную проблему, таким образом мы могли бы помочь вам на уровне дизайна, а не на техническом уровне :)

17
ответ дан 29 November 2019 в 05:21
поделиться

Я не думаю, что вы можете получить то, что хотите. Подумайте об этом, если бы вы реализовали свое предложение: если у вас есть указатель на экземпляр IFoo и вы вызываете functionB () , какой параметр типа вы должны ему указать? Основная проблема заключается в том, что Foo1 :: functionB и Foo2 :: functionB имеют разные подписи и выполняют разные функции.

0
ответ дан 29 November 2019 в 05:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: