Вопрос о борьбе с контравариантностью.Вопрос, связанный с обратным вызовом - PullRequest
1 голос
/ 24 июля 2010

У меня есть следующий фрагмент кода, который не компилируется, когда я пытаюсь создать экземпляр типа CommandGlobal<int>, потому что он пытается переопределить virtual void Execute() const =0; с помощью функции, которая возвращает int.Это дает нековариантную ошибку.

class CommandBase
{
public:
    virtual void Execute() const =0;
};

template<class T>
struct CommandGlobal : CommandBase
{
    typedef boost::function<T ()> Command;
    Command comm;

    virtual T Execute() const
    {
        return comm();
    }
};

template<class T>
struct CommandMemberFunction : CommandBase
{
    typedef boost::function<T (int, std::string)> Command;
    Command comm;
    int entityid;
    std::string mfid;

    virtual T Execute() const
    {
        return comm(entityid, mfid);
    }
}; 

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

Быстрый и грязный ответ: перейдите к Выполнить ссылку на тип результата как void * и сделайте Выполнение частным.Затем оберните Execute в не виртуальную оболочку, которая возвращает T по значению и выполняет приведение.

Может кто-нибудь прояснить этот ответ с небольшим количеством кода.Я был бы очень признателен.

Спасибо всем!

Ответы [ 3 ]

1 голос
/ 24 июля 2010

Я не могу понять, как вы собираетесь использовать эту иерархию. Если вы собираетесь сделать что-то вроде этого:

CommandBase * cb = new CommandGlobal<int>();

тогда что вы положите в свой код для типа ?? ниже:

??type?? result = cb->Execute();

И если вы собираетесь это сделать:

CommandGlobal<int> cg;
int result = cg.Execute();

тогда зачем вообще базовый класс?

В любом случае, вы также можете проверить, что Execute возвращает экземпляр Boost.Any , так как и базовый класс, и подклассы будут возвращать экземпляры одного типа. Затем вы можете в любой момент передать результат нужному типу на сайте вызова, предполагая, что вы сможете выяснить, какой у вас реальный подкласс CommandBase.

0 голосов
/ 24 июля 2010

Вам нужно другое имя, попробуйте что-то вроде:

class CommandBase
{
public:
    virtual void Execute() const =0;
};

template<class T>
struct CommandGlobal : CommandBase
{
    typedef boost::function<T ()> Command;
    Command comm;

    virtual void Execute() const
    {
        ExecuteWithResult();
    }

    virtual T ExecuteWithResult() const
    {
        return comm();
    }
};
0 голосов
/ 24 июля 2010

Я думаю, он имел в виду нечто вроде (немного упрощенное):

<code>
class CommandBase
{
private:
    virtual void* ExecuteMe() const =0;
};<br>
template< class T >
struct CommandGlobal : CommandBase
{
    typedef boost::function Command;
    Command comm;
    T Execute() const
    {
         return <em>((T</em>)(ExecuteMe()));
    }
private:
    virtual void ExecuteMe(void*) const
    {
        return &(comm());
    }
};
template< class T>
struct CommandMemberFunction : CommandBase
{
    typedef boost::function Command;
    Command comm;
    int entityid;
    std::string mfid;<br>
    T Execute() const
    {
         return <em>((T</em>)(ExecuteMe()));
    }
private:
    virtual void* ExecuteMe() const
    {
        return (void*)&(comm(entityid, mfid));
    }
}; 

Хотя это довольно подвержено ошибкам. Я бы посоветовал вам перепроектировать базовый интерфейс, чтобы иметь общий интерфейс для T, чтобы ваш Execute () не возвращал void, а вместо этого IMyClass или что-то подобное.

...