Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can't initialize functor objects when passing derived class in C++

Tags:

c++

functor

This question stems from a previous question I asked here. I cannot use any external libraries or the C++ 11 spec. Meaning I can't use std::bind, std::function, boost::bind,boost::function etc. I have to write it myself. The issue is the following:

Consider the code:

EDIT

Here is a complete program that exhibits the problem as requested:

#include <map>
#include <iostream>


class Command {    
public:
    virtual void executeCommand() = 0;
};

class Functor {
public:
    virtual Command * operator()()=0; 
};

template <class T> class Function : public Functor {
private:
    Command * (T::*fptr); 
    T* obj;                  
public:
    Function(T* obj, Command * (T::*fptr)()):obj(obj),
        fptr(fptr) {}

    virtual Command * operator()(){
        (*obj.*fptr)();   
    }            
};

class Addition:public Command {
public:
    virtual void executeCommand(){
        int x;
        int y;
        x + y;
    }
};

class CommandFactory {
public:
    virtual Addition * createAdditionCommand() = 0;
};

class StackCommandFactory: public CommandFactory {
private:
    Addition * add;
public:
    StackCommandFactory():add(new Addition()) {}

    virtual Addition * createAdditionCommand(){
         return add;
    }
};

void Foo(CommandFactory & fact) {
    Function<CommandFactory> bar(&fact,&CommandFactory::createAdditionCommand);
}

int main() {
    StackCommandFactory fact;
    Foo(fact);
    return 0;
}

The error it gives is "no instance of constructor "Function<T>::Function [with T=CommandFactory] matches the argument list, argument types are: (CommandFactory *, Addition * (CommandFactory::*)())

I think it's complaining because I'm passing it a derived type. I have to use pointers/references to the abstract classes because fact may not be a StackCommandFactory later down the road.

I can't say:

void Foo(CommandFactory & fact){
      Function<CommandFactory> spf(&fact,&fact.createAdditionCommand); //error C2276

}

because of then I receive error C2276 which says (as in the question I linked to) '&' : illegal operation on bound member function expression.

So explicitly my question is: "How do I initialize this functor object so that I can use it with the above mentioned interfaces?"

like image 811
thed0ctor Avatar asked Apr 07 '26 11:04

thed0ctor


1 Answers

Here's a modification of my original answer that seems to do what you need, without using the any functor stuff from C++11 or boost.

#include <vector>
#include <map>
#include <string>

struct Command {};
struct Subtract : Command {};
struct Add : Command {};

class CommandFactory
{
  public:

    virtual Subtract * createSubtractionCommand() = 0;
    virtual Add * createAdditionCommand() = 0;
};

class StackCommandFactory : public CommandFactory
{
  public:

    virtual Subtract * createSubtractionCommand(void);
    virtual Add * createAdditionCommand(void);

    Subtract * sub;
    Add * add;
};

Subtract * StackCommandFactory::createSubtractionCommand(void) { return sub; }
Add * StackCommandFactory::createAdditionCommand(void) { return add; }

class CommandGetterImpl
{
  public:
    virtual CommandGetterImpl* clone() const=0;
    virtual Command* get()=0;
    virtual ~CommandGetterImpl() {};
};

class CommandGetter
{
  public:
  Command* get() { return impl_->get(); }
  ~CommandGetter() { delete impl_; }
  CommandGetter( const CommandGetter & other ) : impl_(other.impl_?other.impl_->clone():NULL) {}
  CommandGetter& operator=( const CommandGetter & other ) {
     if (&other!=this) impl_= other.impl_?other.impl_->clone():NULL;
     return *this;
  }
  CommandGetter() : impl_(NULL) {}
  CommandGetter( CommandGetterImpl * impl ) : impl_(impl) {}
  CommandGetterImpl * impl_;
};

class Parser
{
  public:
    Parser (CommandFactory & fact);

    std::map<std::string, CommandGetter > operations; 
};

template<typename MEMFN, typename OBJ >
class MemFnCommandGetterImpl : public CommandGetterImpl
{
  public:
  MemFnCommandGetterImpl(MEMFN memfn, OBJ *obj) : memfn_(memfn), obj_(obj) {}
  MemFnCommandGetterImpl* clone() const { return new MemFnCommandGetterImpl( memfn_, obj_) ; }
  Command* get() { return (obj_->*memfn_)(); }
  MEMFN memfn_;
  OBJ * obj_;
};


template< typename MEMFN, typename OBJ >
CommandGetter my_bind( MEMFN memfn, OBJ * obj )
{
  return CommandGetter( new MemFnCommandGetterImpl<MEMFN,OBJ>(memfn,obj) );
};

Parser::Parser(CommandFactory & fact)
{
  operations["+"] = my_bind(&CommandFactory::createAdditionCommand, &fact);
  operations["-"] = my_bind(&CommandFactory::createSubtractionCommand, &fact);
}

#include <iostream>
int main()
{
  Add add;
  Subtract sub;

  StackCommandFactory command_factory;
  command_factory.add = &add;
  command_factory.sub= &sub;
  Parser parser(command_factory);

  std::cout<<"&add = "<<&add<<std::endl;
  std::cout<<"Add = " <<  parser.operations["+"].get() <<std::endl;
  std::cout<<"&sub = "<<&sub<<std::endl;
  std::cout<<"Sub = " <<  parser.operations["-"].get() <<std::endl;

  return 0;
}
like image 126
Michael Anderson Avatar answered Apr 09 '26 01:04

Michael Anderson