2013-12-14 10 views
6

Mam odtwarzacz klasy, a niektóre z podklasy Player1, Player2, Player3 rozszerzają odtwarzacz za pomocą C++.
Gracz klasy ma metodę "run", a wszyscy gracze1,2,3 nadpisują "run", aby robić różne rzeczy.
Jak używać wątku C++ 11 z metodą instancji?

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

w "głównych" funkcja utworzyć pewne wystąpienie Player1,2,3
i niektóre C++ 11 gwintu połączenia Metoda "run" tych przykład.

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; 
} 

próbowałem i wiem, że to nie działa,
więc próbuję użyć innej funkcji do wywołania metody instancji.

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; 
} 

ten sposób wydaje się rozwiązać problem, ale muszę tworzyć doRun1, doRun2, doRun3 .... wiele funkcji,
ponieważ parametr doRun1,2,3 należy zadeklarować co jest Gracz1 , 2 lub 3

Nie mogę wymyślić lepszego rozwiązania, czy ktoś może mi pomóc @@?

+5

Co C11 ma z tym wspólnego? Czym dokładnie jest "Wątek", jaki jest podpis tego konstruktora? – Mat

+0

Wow. Czy C11 ma również klasy? – juanchopanza

+0

Przepraszam, moja wina ... Wiedziałem, co to jest to pytanie @@. Mam na myśli C++ 11, a nie C11, poprawię to ... wybacz mi –

Odpowiedz

12

Szukasz czegoś takiego ...

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; 
} 

Jeśli wolisz, możesz też użyć wyrażeń lambda:

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; 
} 

lub, w następstwie DYP sugestia:

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; 
} 
+4

Warto wspomnieć, że wątki będą działały na * kopiach * 'player1',' player2', 'player3'. Jeśli są pożądane semantyki odniesienia, dobrym rozwiązaniem jest 'std :: reference_wrappers' (przekazanie' std :: ref (player1) 'etc). Również 'main' powinien zwrócić' int'. – juanchopanza

+0

Dzięki za rozwiązanie! Spróbuję –

+3

Dlaczego nie po prostu 'thread thread1 (& Player :: run, player1);'? (Wskaźnik do wirtualnej funkcji członka nadal pozwala na dynamiczną wysyłkę.) – dyp

3

To, czego naprawdę szukasz, to std::bind

#include <thread> 
#include <functional> 

using namespace std; 

void main() 
{ 
    Player1 myPlayer1; 

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

Co robisz, to tworzenie obiektu std::function, który akceptuje konstruktor thread. Następnie "wypiekasz" instancję jako część funkcji bind. Ale bądź NAPRAWDĘ ostrożny, ponieważ gdy myPlayer1 wychodzi poza zasięg, ten wskaźnik też. Można zamiast tego:

#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)); 
} 

Dzięki temu żywotność obiektu będzie żywotność wątku, nie żywotność main. To nie jest problem w twoim trywialnym przykładzie, ale jest to problem w prawdziwym życiu.

Aby uzyskać więcej informacji na temat powiązań, zobacz artykuł here i przeczytaj całą sekcję pod adresem functional.

Edit:

Łącząc to, co zostało powiedziane wyżej o dynamicznym wysyłki, jest to również możliwe:

#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); 
} 

ten sposób używasz funkcji wirtualnej klasy bazowej, ale używasz inteligentny wskaźnik do instancji podklasy, dzięki czemu możesz wyjść z pierwotnej funkcji (zakładając, że nie jest to główne, a program się nie kończy). Najlepsze ze wszystkich światów.bind nie jest tu konieczny (ponieważ std::thread już to robi wewnętrznie, a przynajmniej jest to jedna z możliwych implementacji), ale wciąż jest na ogólną ideę "wskaźnika funkcji do czegokolwiek", którego OP potrzebuje.

Powiązane problemy