• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wywołanie metody we wszystkich utworzonych obiektach

Object Storage Arubacloud
+1 głos
304 wizyt
pytanie zadane 7 sierpnia 2017 w C i C++ przez Iamhexi Obywatel (1,330 p.)
edycja 7 sierpnia 2017 przez Iamhexi

Witam!

Piszę program/grę obiektowo z użyciem bibliotek SFML, co nie jest zbyt istotne.

Otóż mam sobie klasę Artifacts, która dziedziczy z klasy Cards. Chciałbym, aby pewna metoda klasy Artifacts (lub Cards) pozwalała ustawić pewną zmienną typu bool we wszystkich istniejących (podczas wykonywania programu) obiektach klasy Artifacts na wartość logiczną false.

5 odpowiedzi

+2 głosów
odpowiedź 7 sierpnia 2017 przez DeBos123 Nałogowiec (44,950 p.)
wybrane 10 sierpnia 2017 przez Iamhexi
komentarz 7 sierpnia 2017 przez Iamhexi Obywatel (1,330 p.)

Pomocne, ale mógłbym prosić o przetłumaczenie? Chociaż skrócić, co należy zrobić po kolei - byle po polsku, a ja już sam dojdę jak to ogarnąć u mnie. Dałoby radę? wink

komentarz 7 sierpnia 2017 przez DeBos123 Nałogowiec (44,950 p.)
Chodzi o to, żeby przy każdym wywołaniu konstruktora dodać nowo utworzony obiekt do tablicy (bądź wektora), a potem po prostu w pętli odwołać się po kolei do każdego obiektu w tablicy.
komentarz 7 sierpnia 2017 przez Iamhexi Obywatel (1,330 p.)
Mniej więcej rozumiem. W razie potrzeby będzie pisał. Dzięki, plusik wpadł :)
+3 głosów
odpowiedź 7 sierpnia 2017 przez mokrowski Mędrzec (155,460 p.)

Robiąc "rejestr tworzonych obiektów", skazujesz się na konieczność ustosunkowania się co do czasu ich życia. Np. co zrobić jeśli zostaną zniszczone? Jak (a raczej kiedy) wyrejestrować je z kontenera? Gdzie trzymać kontener?

Raczej zrobił bym to z użyciem CRTP: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Curiously_Recurring_Template_Pattern

To dany obiekt powinien zapytać o stan pewnej wspólnej zmiennej. Tu przyjąłem że poprzez dziedziczenie określisz jakie rodziny o jakie zmienne pytają. W przykładzie zakładałem że będą komnaty w których magia nie działa. Wszystkie obiekty typu MagicArtifact powinny wtedy utracić właściwość czarowania. Mimo to dalej są artefaktami :-)

Szybki przykład przedstawiający ten sposób... 

#include <iostream>

template<typename T>
class Working {
public:
    static void setWork(bool w) {
        isWork = w;
    }
    static bool isWorking() {
        return Working<T>::isWork;
    }
private:
    static bool isWork;
};

template<typename T>
bool Working<T>::isWork = true;

class Artifact {
public:
    virtual void doWork() = 0;
    virtual ~Artifact() {};
};

class Card : public Artifact, public Working<Artifact> {
public:
    void doWork() override {
        std::cout << "Card doWork() working = " << std::boolalpha
            << Working<Artifact>::isWorking() << '\n';
    }
};

class MagicArtifact: public Artifact, public Working<MagicArtifact> {
public:
    void doWork() override {
        std::cout << "Magic Artifact doWork() working = " << std::boolalpha
            << Working<MagicArtifact>::isWorking() << '\n';
    }
};

class Wand : public Artifact, public Working<MagicArtifact> {
public:
    void doWork() override {
        std::cout << "Wand doWork() working = " << std::boolalpha
            << Working<MagicArtifact>::isWorking() << '\n';
    }
};

class Elixir: public Artifact, public Working<MagicArtifact> {
public:
    void doWork() override {
        std::cout << "Elixir doWork() working = " << std::boolalpha
            << Working<MagicArtifact>::isWorking() << '\n';
    }
};

int main() {
    Card c;
    Wand w;
    Elixir e;

    // Do testów więc w trybie "spagetti" :-)
    std::cout << "Artifact <- true, MagicArtifact <- false\n";
    Working<Artifact>::setWork(true);
    Working<MagicArtifact>::setWork(false);

    c.doWork();
    w.doWork();
    e.doWork();

    std::cout << "Artifact <- false, MagicArtifact <- true\n";
    Working<Artifact>::setWork(false);
    Working<MagicArtifact>::setWork(true);

    c.doWork();
    w.doWork();
    e.doWork();

}

Nawet mógłbyś nie dziedziczyć tylko wołać określone rodzaje wspólnych zmiennych. Być może będziesz chciał sprawdzać typ, stąd relacja dziedziczenia klasycznego CRTP :-)

Dodatkowo pozwoli Ci to np. implementować takie zachowania w logice gdzie "jeśli w klasie Wand (która jest typu Artifact i także MagicArtifact) Artifact nie działa to nie jest ważne czy MagicArtifact działa a jak Artifact działa to istotne jest czy MagicArtifact działa" :-)

komentarz 7 sierpnia 2017 przez Iamhexi Obywatel (1,330 p.)
Bardzo dziękuję za pomoc, ale nie jestem na takim poziomie zaawansowania. Właściwie to lepiej byłoby gdybym podał gdzieś kod, bo z tym co napisałeś (za co jestem ogromnie wdzięczny) nie za wiele rozumiem. Czy mógłbym pokazać gdzieś kod, licząc na analizę mojego (prawdopodobnie) prostego do rozwiązania problemu, z którym sobie nie radzę?
komentarz 7 sierpnia 2017 przez mokrowski Mędrzec (155,460 p.)

Ok, tylko wydziel to co umieścisz do małego przykładu który poddaje się kompilacji oraz opisz pożądane rodzaje zachowań. Ogólnie chodzi o to żebyś nie robił rejestru obiektów bo to jest i ciężkie i podatne na błędy. Stosując prosty szablon do klasy ze statycznymi elementami, możesz kontrolować to jakie zmienne są wspólne jakie są indywidualne dla wszystkich obiektów danej klasy a jakie jeszcze bardziej ogólne dla klasy "super-nadrzędnej" :-) Powinieneś mieć jakiś ważki powód by te zmienne były "indywidualne dla każdej klasy" i "przechodzić po obiektach" (np. wzorzec Visitor) Tu takiego powodu nie ma.. chyba że przykład mnie przekona :-) 

komentarz 7 sierpnia 2017 przez Iamhexi Obywatel (1,330 p.)
Piszę sobie karciankę, więc: cards.h - http://wklejto.pl/291706

cards.cpp - http://wklej.org/id/3231273/

Te opisy łamaną angielszczyzną były dla mnie, kluczowe informacje podałem w języku polskim. Dodałem tylko najistotniejsze pliki.
komentarz 7 sierpnia 2017 przez mokrowski Mędrzec (155,460 p.)
1. Poddaje się kompilacji.

2. Opisz pożądane zachowanie.
komentarz 7 sierpnia 2017 przez Iamhexi Obywatel (1,330 p.)
Kompiluje się gdyż nie daje pożądanego efektu.

Interesuje mnie użycie działającego "przestawiania" w miejscu //TUTAJ CHCĘ USTAWIĆ VISIBILITY WSZYSTKICH OBIEKTÓW KLASY ARTIFACT NA FALSE.
komentarz 7 sierpnia 2017 przez criss Mędrzec (172,590 p.)
@mokrowski - a dlaczego uważasz, że rozwiązanie podane przez DeBos123 jest słabe? (tak przynajmniej zrozumiałem pierwszy akapit twojej odpowiedzi)
IMHO w pełni wystarcza do osiągnięcia celu. Klasa Artifact zawiera statyczny std::set do którego przy konstrukcji obiektu jest dodawany wskaźnik. Podobnie w destruktorze jest usuwany. Teraz wystarczy tylko statyczna metoda iterująca po naszym kontenerze ustawiająca nasz member każdego obiektu na true.
komentarz 7 sierpnia 2017 przez mokrowski Mędrzec (155,460 p.)
@Criss - nie jest "słabe" bo tego pojęcia nie użyłem :-) Napisałem o konsekwencjach takiej implementacji. To zresztą potwierdzasz. Potrzebna jest implementacja logiki obsługującej czas życia obiektu w kontenerze. Jeśli przestawienie właściwości w danym obiekcie wiązało by się np. ze sprawdzeniem jego innych atrybutów zmieniających się na etapie działania i na tej podstawie ew. przestawienie atrybutu, pewnie decydował bym się na iterowanie po obiektach. Jeśli potrzebna była by np. serializacja obiektów, także rejestr.

W mojej ocenie atrybut wspólny dla wielu obiektów jest po prostu statyczny a konieczność różnicowania dostępu do niego (per rodzina wynikająca z hierarchii klas) można osiągnąć prostym szablonem. Umożliwi on określenie jaka zmienna jest wspólna dla jakich rodzin. Polimorfizm statyczny jest tu (w mojej ocenie) wystarczający.
komentarz 8 sierpnia 2017 przez mokrowski Mędrzec (155,460 p.)
+1 głos
odpowiedź 7 sierpnia 2017 przez WireNess Stary wyjadacz (11,240 p.)
Chodzi Ci o to, żeby wszystkie istniejące obiekty klasy Arrifacts miałby zmienną o takiej samej wartości?

Np. Masz 100 obiektów tej klasy i składową: int var. Chcesz ustawić tą zmienną tak aby każdy obiekt tej klasy miał tą składową ustawioną załóżmy na 5?

Jeżeli ta zmienna dla wszystkich obiektów ma być taka sama to można wykorzystać zmienną ze słowem static. Jeżeli o to Ci chodzi to odpisz, albo daj plusa to napiszę jak to zrobić ;)
komentarz 7 sierpnia 2017 przez Iamhexi Obywatel (1,330 p.)
Chodzi o to, żeby zmienić tą zmienna. Nie może być (chyba) statyczna, gdyż podczas inicjacji ma inną wartość niż po zmianie. Wartość początkowa ma się różnić od wartości po wykorzystaniu tej metody na wszystkich utworzonych obiektach.
1
komentarz 7 sierpnia 2017 przez WireNess Stary wyjadacz (11,240 p.)

Nie jestem pewien czy dobrze zrozumiałem, więc pokaże Ci przykład :D

 

W pliku hpp w składowych (private) dodajesz zmienną bez inicjalizacji ze słowem static:

static int zmienna;

W pliku cpp dodajesz inicjalizacje poza wszelkimi metodami! (Zauważ, że słowo static znika):

int Klasa::zmienna = 1;

Teraz możesz dodać metodę, która zmieni wartość dla wszystkich utworzonych obiektów tak jak powyżej

 

Żebyś lepiej zrozumiał podam Ci prosty przykład liczący liczbę utorzonych obiektów:


//klasa.hpp

#include <iostream>

using namespace std;

class Klasa
{
public:
    Klasa();
    ~Klasa();

    void liczba();

private:
    static int objNum;
};

-

//klasa.cpp

#include "klasa.cpp"

int Klasa::objNum=0;
Klasa::Klasa()
{
   objNum++;
}
Klasa::~Klasa()
{
   objNum--;
}
void Klasa::liczba()
{
    cout << "Liczba obiektów: " << objNum << endl;
}

-

//main.cpp

#include "klasa.hpp"

int main()
{
    using namespace std;
    {
        Klasa o1,o2;
        liczba();
    }

    liczba();

    return 353;
}

 

1
komentarz 7 sierpnia 2017 przez Iamhexi Obywatel (1,330 p.)
Jestem bardzo wdzięczny za przybliżenie mi słowa static wobec zmiennych, spróbuję to rozkminić. Chociaż rozwiązanie powyżej wydaje mi się bardziej intuicyjne. Dziękuję za poświęcony czas, spróbuję ogarnąć to rozwiązanie. Pozdrawiam :)
+1 głos
odpowiedź 7 sierpnia 2017 przez vector Dyskutant (9,200 p.)

Nie jest to idealne rozwiązanie, aczkolwiek jak nie chcesz tworzyć listy obiektów do powiadomienia to myślę że jest akceptowalne.

#include <bits/stdc++.h>

template<typename T, size_t N>
class SharedlocalVar {
public:
    using Pair = std::pair<T, size_t>;

    void setLocal(const T &value) {
        local.first = value;
        local.second = ++uuid;
    }

    void setLocal(T &&value) {
        local.first = std::move(value);
        local.second = ++uuid;
    }

    void setGlobal(const T &value) {
        global.first = value;
        global.second = ++uuid;
    }

    void setGlobal(T &&value) {
        global.first = std::move(value);
        global.second = ++uuid;
    }

    const T& get(void) const {
        return global.second < local.second ? local.first : global.first;
    }

    T& get(void) {
        return global.second < local.second ? local.first : global.first;
    }

protected:
    static Pair global;
    static size_t uuid;
    Pair local;
};

template<typename T, size_t N>
typename SharedlocalVar<T, N>::Pair SharedlocalVar<T, N>::global = {T(), 0};

template<typename T, size_t N>
size_t SharedlocalVar<T, N>::uuid = 0;

class Foo : public SharedlocalVar<bool, 0> {
};

int main(void) {
    Foo a, b;
    a.setLocal(true);
    b.setLocal(false);
    std::cout << a.get() << " " << b.get() << std::endl;
    a.setGlobal(true);
    std::cout << a.get() << " " << b.get() << std::endl;
    a.setGlobal(false);
    std::cout << a.get() << " " << b.get() << std::endl;
    a.setLocal(true);
    std::cout << a.get() << " " << b.get() << std::endl;
    return 0;
}

 

+1 głos
odpowiedź 8 sierpnia 2017 przez maly Nałogowiec (37,190 p.)
struct Object
{
	int value;
	std::vector<Object*> &container;

	Object(int value, std::vector<Object*> &container)
	:value(value), container(container)
	{
	}

	void setForAll(int value)
	{
		for(std::size_t i = 0; i < container.size(); ++i)
			container[i]->value = value;
	}
};


std::vector<Object*> ObjectsContainer;

for(int i = 0; i < 10; ++i)
	ObjectsContainer.push_back(new Object(i, ObjectsContainer));

ObjectsContainer[3]->setForAll(5);

 

Podobne pytania

0 głosów
1 odpowiedź 205 wizyt
pytanie zadane 14 kwietnia 2020 w C i C++ przez nanautzin Obywatel (1,510 p.)
0 głosów
1 odpowiedź 190 wizyt
pytanie zadane 5 października 2017 w Java przez newUser Użytkownik (520 p.)
0 głosów
1 odpowiedź 197 wizyt

92,555 zapytań

141,403 odpowiedzi

319,557 komentarzy

61,940 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...