C ++: calling the correct method of a derived class by argument types

Say we have a base class and its two derived classes; The base class owns the execute method, and each derived class implements a different version of this method with different types and number of arguments; I cannot use the virtual method, because the signature must be the same for each derived class; My goal is to offer a basic execution method that takes any arguments, subtracts their types and sends them to the correct method in the right derived class; I looked at the visitor template, but I am looking for a more flexible and elegant solution;

edit . I want to save these classes in a vector, so I need a base class

Here is my attempt (I don’t know what to put in the body of the database to execute) under gcc 4.5 :

class Base {

  public:

  Base();
  ~Base();

  template<typename ...Args>
  void execute(Args... arg)
  {
    //calls the right method
    //execute(int i) or execute(int i, float f)
    //as Args are int or int and float
  }

};

class DerivedA : public Base
{

  public:

  DerivedA();
  ~DerivedA();

  void execute(int i){ /*do something with i*/}

};

class DerivedB : public Base
{

  public:

  DerivedB();
  ~DerivedB();

  void execute(int i, float f){/*do something with i and f*/}

};

void test()
{
  Base* b1 = new DerivedA();
  Base* b2 = new DerivedB();

  int i = 5;
  b1->execute(i); //should call DerivedA.execute(int i)
  float f = 5.0f;
  b2->execute(i, f); //should call DerivedB.execute(int i, float f)

}
+5
source share
4 answers

The intermediate class between the base and the derived class is used below:

#include <utility>
#include <iostream>
#include <stdexcept>

template<typename... Args> class Intermediate;

class Base
{
public:
  virtual ~Base() {}

  template<typename ...Args>
  void execute(Args... args)
  {
    typedef Intermediate<Args...>* pim;
    if (pim p = dynamic_cast<pim>(this))
    {
      p->execute(std::forward<Args>(args)...);
    }
    else
    {
      throw std::runtime_error("no suitable derived class");
    }
  }
};

template<typename... Args> class Intermediate:
  public Base
{
public:
  virtual void execute(Args ... arg) = 0;
};

class DerivedA:
  public Intermediate<int>
{
public:
  void execute(int i)
  {
    std::cout << "DerivedA: i = " << i << "\n";
  }
};

class DerivedB:
  public Intermediate<int, float>
{
public:
  void execute(int i, float f)
  {
    std::cout << "DerivedB: i = " << i << ", f = " << f << "\n";
  }
};

int main()
{
  Base* b1 = new DerivedA();
  Base* b2 = new DerivedB();

  int i = 5;
  b1->execute(i); //should call DerivedA.execute(int i)
  float f = 5.0f;
  b2->execute(i, f); //should call DerivedB.execute(int i, float f)
}
+5
source

In the base class, you cannot have an unlimited number of virtual functions (= unbounded). You must decide what features should be available and declare them. Otherwise, you won’t need virtual functions, and you can just do some sending the compile time, perhaps just by overload resolution like this:

struct Base
{
   void foo(int a)          { dynamic_cast<DerA*>(this)->fooimpl(a); }
   void foo(int a, float b) { dynamic_cast<DerB*>(this)->fooimpl(a, b); }
   void foo(bool a, char b) { dynamic_cast<DerC*>(this)->fooimpl(a, b); }

   virtual ~Base() { }  // dynamic cast requires polymorphic class
};

Of course, you should add validation:

if (DerA * p = dynamic_cast<DerA*>(this)) { p->fooimpl(a)); }
+1
source

?

, , . , ++ , (. ++). . ++ Bjarne Stroustroup .

(.. Base*), ( ):

#include <iostream>

class DerivedA //: public Base
{
public:
    void execute(int i)
    { 
        std::cout << "I'm DerivedA::execute(int)! " << std::endl; 
    }
};

class DerivedB //: public Base
{
public:
    void execute(int i, float f) 
    {
        std::cout << "I'm DerivedB::execute(int, float)! " << std::endl; 
    }
};

template<typename Class, typename... Args>
void execInvoker(Class* obj, Args... args)
{
    static_cast<Class*>(obj)->execute(std::forward<Args>(args)...);
}

int main(int argc, char* argv[])
{
    DerivedA a;
    DerivedB b;

    int i = 5;
    float f = 5.2f;
    execInvoker(&a, i);
    execInvoker(&b, i, f);
}

, execute, ( ). g++ 4.6, :

$ g++ -std=c++0x -Wall variadic.cpp 
$ ./a.out 
I'm DerivedA::execute(int)! 
I'm DerivedB::execute(int, float)!

, - .

template<typename Class>
class Proxy
{
private:
    Class* obj;

public:
    Proxy(Class* _obj) : obj(_obj) {}

    template<typename... Args>
    void execute(Args... args)
    {
        obj->execute(std::forward<Args>(args)...);
    }
};

:

Proxy<DerivedA> proxy(&a);
proxy.execute(i);

, - , :

template<typename Class>
void proxyUser(Proxy<Class>& p)
{
    p.execute(4, 0.3f);
}

execute. .

+1

, , " ":

- , , ()

: - "" :

target.execute(client);

, (, ):

dispatchTable.execute(client, *this);  //-- target calls this

( ) :

<get arguments from client>
target.specific_execute(arguments)

, , . , target::execute :

client.execute(target);

client::execute(target), , :

target.specific_execute(args);

execute, . execute.

( ), , , ( ), , .

class Client;
struct Base {
    virtual void dispatch(Client& c);
    void execute(Base& b) {
        std::cout << "void execute(Base&)" << std::endl;
    }
};

struct DerivedA : public Base {
    void exec(int i){ 
        /*do something with i*/
        std::cout << "void execute(int i)" << std::endl;
    }
};

struct DerivedB : public Base {
    void exec(int i, float f)
    {
        std::cout << "void execute(int i, float f)" << std::endl;
    }
};

struct Client {
    int i;
    float f;

    void execute(Base& obj) {
    }
    void execute(DerivedA& obj) {
        obj.exec(i);
    }
    void execute(DerivedB& obj) {
        obj.exec(i, f);
    }
    void doTest() {
        Base* b1 = new DerivedA();
        Base* b2 = new DerivedB();
        b1->dispatch(*this);
        b2->dispatch(*this);
    }
};

void Base::dispatch(Client& c) {
    c.execute(*this);
}
void DerivedA::dispatch(Client& c) {
    c.execute(*this);
}
void DerivedB::dispatch(Client& c) {
    c.execute(*this);
}

int main (int argc, char * const argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";

    Client c;
    c.doTest();

    return 0;
}
0

All Articles