8

I have a Class Player, and some sub-Class Player1, Player2, Player3 extends Player using C++.
Class Player have a method "run", and all of Player1,2,3 will override "run" to do different things.

class Player {
public:
    virtual void run();
}
class Player1: public Player {
public:
    void run();
}

In "main" function I will create some instance of Player1,2,3
and some C++11 thread call method "run" of these instance.

int main() {
    Player1 player1;
    Player2 player2;
    Player3 player3;
    Thread thread1(player1.run, this);
    Thread thread2(player2.run, this);
    Thread thread3(player3.run, this);
    thread1.join();
    thread2.join();
    thread3.join();

    return 0;
}

I have tried and I know it doesn't work,
so I try to use another function to call instance method.

function doRun1(Player1 player){
    player.run();
}

int main() {
    Player1 player1;
    Player2 player2;
    Player3 player3;
    Thread thread1(doRun1, player1);
    Thread thread2(doRun2, player2);
    Thread thread3(doRun3, player3);
    thread1.join();
    thread2.join();
    thread3.join();

    return 0;
}

This way seems to solve problem, but I have to create doRun1, doRun2, doRun3.... lots of function,
because the parameter of doRun1,2,3 need to be declare which is Player1,2 or 3

I can't think any better solution, can someone help me @@?

Azure Chen
  • 859
  • 1
  • 12
  • 21

2 Answers2

13

You are looking for something like this...

class Player {
public:
    virtual void run() = 0;
};

class Player1: public Player {
public:
    void run(); // you must implement then for Player1, 2, 3
};

void doRun(Player * player)
{
    player->run();
}

int main(int argc, char * argv[]) {
    Player1 player1;
    Player2 player2;
    Player3 player3;

    thread thread1(doRun, &player1);
    thread thread2(doRun, &player2);
    thread thread3(doRun, &player3);

    thread1.join();
    thread2.join();
    thread3.join();

    return 0;
}

If you prefer, you can also use lambda expressions:

int main(int argc, char * argv[]) {
    Player1 player1;
    Player2 player2;
    Player3 player3;

    thread thread1([&] (Player * player) { player->run(); }, &player1);
    thread thread2([&] (Player * player) { player->run(); }, &player2);
    thread thread3([&] (Player * player) { player->run(); }, &player3);

    thread1.join();
    thread2.join();
    thread3.join();

    return 0;
}

Or, following DyP suggestion:

int main(int argc, char * argv[]) {
    Player1 player1;
    Player2 player2;
    Player3 player3;

    thread thread1(&Player::run, player1);
    thread thread2(&Player::run, player2);
    thread thread3(&Player::run, player3);

    thread1.join();
    thread2.join();
    thread3.join();

    return 0;
}
Wagner Patriota
  • 5,494
  • 26
  • 49
  • 4
    It might be worth mentioning that the threads will run on *copies* of `player1`, `player2`, `player3`. If reference semantics are desired, `std::reference_wrappers` are a good option (passing `std::ref(player1)` etc). Also, `main` should return `int`. – juanchopanza Dec 14 '13 at 18:40
  • 3
    Why not just `thread thread1(&Player::run, player1);`? (A pointer to a virtual member function still allows dynamic dispatch.) – dyp Dec 14 '13 at 21:56
  • you are right Dyp... much better than my quick solution... I will edit to improve the answer. I just followed the `doRun()` he created so I kept it... but in fact the original wish is just to call the `Player::run()` ;-) – Wagner Patriota Dec 15 '13 at 05:45
  • 3
    Just be careful about that last example, as it is taking a copy of the arguments, which means each new thread is taking a copy of each player subclass object. This may or may not be what is desired. – Kevin Anderson Dec 19 '13 at 01:27
4

What you're ACTUALLY looking for is std::bind

#include <thread>
#include <functional>

using namespace std;

void main()
{
    Player1 myPlayer1;

    thread thread1(bind(&Player1::run, &myPlayer1));
}

What you're doing is creating a std::function object, which the thread constructor accepts. Then you're "baking in" the instance as part of the bind function. But be REALLY careful with this, as when myPlayer1 goes out of scope, that pointer does too. You may want this instead:

#include <thread>
#include <functional>
#include <memory>

using namespace std;

void main()
{
    shared_ptr<Player1> ptr_myPlayer1(new Player1());

    thread thread1(bind(&Player1::run, ptr_myPlayer1));
}

This allows the lifetime of the object to be the lifetime of the thread, not the lifetime of main. That's not an issue in your trivial example, but it's an issue in real life.

See here for more information on bind, and read the whole section on functional too.

Edit:

Combining what was said above about dynamic dispatch, this is also possible:

#include <thread>
#include <memory>

using namespace std;

void main()
{
    shared_ptr<Player> ptr_myPlayer(new Player1());  // Works because holds a pointer to base class

    thread thread1(&Player::run, ptr_myPlayer1);
}

This way you're using the virtual function of the base class, but you're using a smart pointer to a sub-class instance so you can exit the original function (assuming not main and the program isn't ending). Best of all worlds. bind isn't necessary here (since std::thread is already doing this internally, at least that's one possible implementation) but it's still on the general idea of "function pointer to anything" that the OP is wanting.

Kevin Anderson
  • 6,850
  • 4
  • 32
  • 54