virtual function template - design probelm

Discussion in 'C++' started by Sebastian Faust, Oct 28, 2003.

  1. Hi,

    I have a design problem about which I am thinking now for a while and still
    couldnt find any help in deja. What I need is something like a virtual
    function template. I know that this is not possible, so I need "something
    like" a virtual function template. I read in some threads that there is a
    workaround using the visitor pattern. I read therefore in the book "Modern
    c++ Design" about this pattern, but couldnt find any help to my approach. So
    now to my problem:

    class Instrument
    {
    public:
    Instrument(Instrument* ptrSuccessor) : m_ptrSuccessor(ptrSuccessor)
    { }
    template<typename Command> // I know this is not
    possible, but that's what I wanna do
    void virtual handle_command(Command& op) = 0;
    protected:
    Instrument* m_ptrSuccessor;
    };

    class ConcreteInstrument : public Instrument
    {
    public:
    template<typename Command> // I know this is not
    possible, but that's what I wanna do
    void virtual handle_command(Command& op)
    {
    if(op->is_instrument())
    {
    _state = op->get_state();
    }
    else
    m_ptrSuccessor->handle_command(op);
    }
    protected:
    int _state; // this could be any other type, maybe the type
    will later be defined in form of a template parameter of the class
    // ConcreteInstrument, so then
    ConcreteInstument will be a class template.
    };

    template<typename Type, Type TYPE>
    class Command
    {
    public:
    Command(Type& state) : _state(state) { };
    public:
    virtual bool is_instrument()
    {
    if(_state == TYPE)
    return true;
    else
    return false;
    }
    virtual Type get_state() { return _state; }
    protected:
    Type _state;
    };

    Usually in Command._state there is some kind of raw data which includes
    type-info, and the real state. In the ConcreteInstrument we then only need
    the real state-data, so usually the get_state and is_instrument function
    will perform some extracting processing to extract the needed data out of
    the raw-data.

    For any help on my problem thanks in advance,
    Sebastian
    Sebastian Faust, Oct 28, 2003
    #1
    1. Advertising

  2. Sebastian Faust

    Kevin Saff Guest

    "Sebastian Faust" <> wrote in message
    news:bnltqk$1267hb$-berlin.de...

    > class ConcreteInstrument : public Instrument
    > {
    > public:
    > template<typename Command> // I know this is not
    > possible, but that's what I wanna do
    > void virtual handle_command(Command& op)
    > {
    > if(op->is_instrument())
    > {
    > _state = op->get_state();
    > }
    > else
    > m_ptrSuccessor->handle_command(op);
    > }
    > protected:
    > int _state; // this could be any other type, maybe the type
    > will later be defined in form of a template parameter of the class
    > // ConcreteInstrument, so then
    > ConcreteInstument will be a class template.
    > };


    I'm not sure exactly what you're shooting for, but it does look from your
    example like the visitor pattern may help. Here's the basic idea:

    // base class for all commands
    class Command
    {
    public:
    // this line MUST be reimplemented in every command type, even though it
    looks the same.
    virtual void accept (CommandVisitor& visitor) {visitor.visit (*this);}
    };

    // base class for all visitors
    class CommandVisitor
    {
    public:
    virtual void visit (Command& op) {}
    virtual void visit (InstrumentCommand& op) {visit
    (static_cast<Command&>(op);}
    virtual void visit (AnotherCommand& op) {visit
    (static_cast<Command&>(op);}
    virtual void visit (YetAnotherCommand& op) {visit
    (static_cast<Command&>(op);}
    };

    OK, now we want something that does one thing for InstrumentCommand's and
    another for any other command type. So, all we need to write is this:

    class InstrumentCommandVisitor : public CommandVisitor
    {
    public:
    void visit (InstrumentCommand& op) {_state = op->get_state();}
    void visit (Command& op)
    {m_ptrSuccessor->handle_command(op);}
    };

    Now, in order to use this system, we say something like:

    Command& command = getCommand();
    command.accept (visitor);

    Now, the actual type of the command will determine which of visitor's
    overloaded visit functions will get called. Note that the functions for the
    CommandVisitor let you override for just the Command types you are
    interested in, and not worry about the rest.

    The biggest problem with this is you will need to add a function to
    CommandVisitor every time you add a new Command type. Depending on your
    needs, an RTTI visitor may be more appropriate.

    I hope this made sense and/or helped.
    Kevin Saff, Oct 28, 2003
    #2
    1. Advertising

  3. Hi,

    > class Command
    > {
    > public:
    > // this line MUST be reimplemented in every command type, even though

    it
    > looks the same.
    > virtual void accept (CommandVisitor& visitor) {visitor.visit (*this);}
    > };

    The problem here is that the Command is a class template. So with different
    template parameters I always get a new type. Now if I wanna give an object
    of this type to the visit function as you did then there is no type Command,
    there are only different Types like:
    Command<int, 3>
    Command<float, 7.0>
    and so on. So the problem is that I can't give to the virtual function visit
    a from Command derived class Object, cause there is no Command-Class.

    That's why in my opinion I have to simulate something like virtual function
    templates, cause than I can give the different Command-Types to that
    virtual-function of the Instrument-Class and cause the function
    handle_command is virtual always the right handle_command-function of the
    right Instrument-Class will be called.

    If you need any further information just ask again.

    Thanks in advance
    Sebastian
    Sebastian Faust, Oct 28, 2003
    #3
  4. Sebastian Faust

    Kevin Saff Guest

    "Sebastian Faust" <> wrote in message
    news:bnmbvc$132omg$-berlin.de...> The problem here is
    that the Command is a class template. So with different
    > template parameters I always get a new type. Now if I wanna give an object
    > of this type to the visit function as you did then there is no type

    Command,
    > there are only different Types like:
    > Command<int, 3>
    > Command<float, 7.0>


    Are floats allowed as template parameters? I think that's nonstandard.

    > and so on. So the problem is that I can't give to the virtual function

    visit
    > a from Command derived class Object, cause there is no Command-Class.


    How about just making a Command class, then? It looks like in that function
    you are only using the "is_instrument" member of Command, which does not
    take or return anything relying on the template parameter.

    class Command
    {
    public:
    virtual bool is_instrument()=0;
    };

    template<typename Type, Type TYPE>
    class CommandImpl : public Command
    {
    // ...
    };

    This looks like it does what you want.
    Kevin Saff, Oct 28, 2003
    #4
  5. Hi,

    >
    > How about just making a Command class, then? It looks like in that

    function
    > you are only using the "is_instrument" member of Command, which does not
    > take or return anything relying on the template parameter.
    >
    > class Command
    > {
    > public:
    > virtual bool is_instrument()=0;
    > };
    >
    > template<typename Type, Type TYPE>
    > class CommandImpl : public Command
    > {
    > // ...
    > };
    >
    > This looks like it does what you want.


    Yes that's what I want to do, but the problem is that Command has to be a
    class template, cause the the get_state() function has different
    return-types in dependency of the Type set by the template definition. So I
    still have the problem that I have to call a virtual member function (
    handle_command ) of the instrument class with different types. Therefore I
    would need "something like virtual function templates". But I still couldnt
    figure out how to work around this. And that's what I am searching for.

    If you have any further questions.... cause my english is not that perfect,
    then just ask me.

    Thanks in advance
    Sebastian
    Sebastian Faust, Oct 29, 2003
    #5
  6. Hi,

    >
    > This definitely sounds like a job for the visitor pattern. See my first
    > reply for how to implement it. Basically, you should have a base Command
    > class, and derive classes of that with whatever data is appropriate. Say
    > you have a FloatCommand object, then if the visitor implements visit
    > (FloatCommand&) it can access specific member functions of the

    FloatCommand
    > class, and is not limited to the capabilities of the base Command class.
    >

    Yes I thought about the Visitor pattern too, but I don't know exactly how to
    apply it in my case. I think the visited-object is the Instrument and the
    Visitor is the Command, or am I wrong? But how can I handle the different
    return types in the Command class?

    Thanks in advance
    Sebastian
    Sebastian Faust, Oct 30, 2003
    #6
  7. Sebastian Faust

    Kevin Saff Guest

    "Sebastian Faust" <> wrote in message
    news:bnr125$14oeri$-berlin.de...
    > Yes I thought about the Visitor pattern too, but I don't know exactly how

    to
    > apply it in my case. I think the visited-object is the Instrument and the
    > Visitor is the Command, or am I wrong? But how can I handle the different
    > return types in the Command class?


    You have it backwords. Since the Instrument acts on the Command, the
    Instrument will be the visitor. So you can have:

    class Command;
    class CommandInt;
    class CommandDouble;

    class Instrument
    {
    public:
    virtual void visit (Command&) {}
    virtual void visit (CommandInt& c) {visit (static_cast<Command&> (c));}
    virtual void visit (CommandDouble& c) {visit (static_cast<Command&>
    (c));}
    virtual ~Instrument() {}
    };

    class Command
    {
    public:
    virtual void accept (Instrument& v) =0;
    virtual ~Command() {}
    };

    class CommandInt
    {
    public:
    void accept (Instrument& v) {v.visit (*this);}
    int getInt() {return 5;}
    };

    class CommandDouble
    {
    public:
    void accept (Instrument& v) {v.visit (*this);}
    double getDouble() {return 3.14159;}
    };


    class MyInstrument : public Instrument
    {
    public:
    void visit (Command&) {std::cout << "Visited unknown command" <<
    std::endl;}
    void visit (CommandInt& c) {
    std::cout << "Visited int command with value: " << c.getInt() <<
    std::endl;
    }

    void visit (CommandInt& c) {
    std::cout << "Visited double command with value: " << c.getDouble()
    << std::endl;
    }
    };

    int main()
    {
    Command *ci = new CommandInt;
    Command *cd = new CommandDouble;

    MyInstrument v;

    ci-> accept (v);
    cd-> accept (v);

    delete ci;
    delete cd;
    };

    As you can see, the visitor sees the actual type of the command. This is
    the point of the pattern. Please see _Design_Patterns_ or search for
    "visitor pattern" if you need more info.
    Kevin Saff, Oct 30, 2003
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    1,013
    David Binnie
    Mar 17, 2006
  2. IK
    Replies:
    2
    Views:
    605
    hemraj
    Jul 23, 2004
  3. Replies:
    4
    Views:
    368
    mlimber
    Jan 23, 2006
  4. joe
    Replies:
    5
    Views:
    343
  5. Yvan J. Gagnon
    Replies:
    4
    Views:
    103
Loading...

Share This Page