Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

wskaznik do elementu klasy wewnątrz klasy

Ostatnio zmodyfikowano 2015-07-03 17:33
Autor Wiadomość
qrchack
Temat założony przez niniejszego użytkownika
wskaznik do elementu klasy wewnątrz klasy
» 2015-07-01 17:14:34
Witam serdecznie!

Zanim przejdę do opisu problemu pozwolę sobie zilustrować sytuację na polu bitwy
Mam 3 klasy
C/C++
class cGlowna
{
private:
    std::vector < cObiekt > tObiekty;
   
public:
    void RobCosZObiektami( void );
   
};

class cObiekt
{
private:
    std::vector < cModel > tModele;
   
public:
    void RobCos( void );
   
    cObiekt();
};

class cModel
{
private:
    int i;
    int * wsk_na_i;
   
    int wynik_obliczen;
public:
    void set_p_i( int * _i ) { wsk_na_i = _i; }
    int * ret_p_i( void ) { return & i; }
   
    void oblicz( void ) { wynik_obliczen = i * wsk_na_i; }
};
Oczywiście nazwy klas i ich składowe nie odzwierciedlają rzeczywistości, nie ma to jednak znaczenia, chodzi mi o samą zasadę.
W konstruktorze cObiekt tworzę sobie dwa cModel

 tModele.resize(tModele.size()+2);

a w RobCos chcę przypisać do wskaźnika pierwszego modelu adres i drugiego modelu
C/C++
void cObiekt::RobCos( void )
{
    tModele[ 1 ].set_p_i( tModele[ 0 ].ret_p_i() );
}
I to nie działa tak, jak powinno... I doszedłem dlaczego (chyba). Odkryłem, że inny adres jest jeśli wewnątrz klasy cModel (np. w konstruktorze) zrobię wsk_na_i = &i, a inny, jeśli z main wpisze glowny_wsk_na_i = &Glowna.tObiekt[0].tModel[0].i;

I moje pytanie brzmi - jak wewnątrz klasy uzyskać "zewnętrzny" adres jej składowej?

Jeśli nie wyraziłem się dojść jasno, to pytajcie, postaram się doprecyzować o co mi chodzi
P-134221
RazzorFlame
» 2015-07-01 19:33:46
Kod dawaj pomiędzy
[cpp][/cpp]
Jeżeli dodajesz element do Vectora to każdy wskaźnik na element Vectora staje się nieprawidłowy.
Przykład:
C/C++
std::vector < int > VecI;
VecI.push_back( 1 );
std::cout << &( VecI[ 0 ] ) << std::endl;
VecI.push_back( 2 );
std::cout << &( VecI[ 0 ] ) << std::endl;
W tym momencie dostaniesz 2 inne adresy.

Jeżeli chcesz by adres był ten sam utwórz Vector wskaźników na coś np:
C/C++
std::vector < int *> VecI;
VecI.push_back( new int( 1 ) );
std::cout << VecI[ 0 ] << std::endl;
VecI.push_back( new int( 2 ) );
std::cout << VecI[ 0 ] << std::endl;
W tym momencie dostaniesz 2x ten sam adres.
P-134226
qrchack
Temat założony przez niniejszego użytkownika
» 2015-07-01 20:37:57
Dzięki, spróbuję, ale od razu zapytam

C/C++
class cModel
{
private:
    (...)
    D3DXMATRIX matTransformFinal;
    D3DXMATRIX matIdentity;
   
public:
    (...)
    D3DXMATRIX * matTransformParent;
    D3DXMATRIX matTransform;
   
    void Transform( void ) { matTransform = matRotateX * matRotateY * matRotateZ * matTranslate * matHOOK * * matTransformParent;
        matTransformFinal = matPOI * matTransform; }
    cModel();
    ~cModel();
};

cModel::cModel
{
    (...)
    matTransformParent = & matIdentity;
}

Od razu mówię, że macierze są zdefioniowane gdzie trzeba ;)

Problem polega na tym, że przy obecnej konfiguracji w momencie wywołania konstruktora matTransformParent wskazuje co trzeba (sprawdziłem w debuggerze), ale gdy wywoływana jest funkcja Transform matTransformParent wskazuje już jakieś losowe miejsce.

Czy zamiana std::vector <cModel> tModele na std::vector <cModel * > tModele rozwiąże problem?
I czy
C/C++
void cObiekt::whatever( void )
{
    tModele[ 1 ].matTransformParent = & tModele[ 0 ].matTransform;
}
to zadziała poprawnie? W sensie, czy matTransformParent będzie po wieki wiekow (czyli do momentu zabicia t[1] i t[0]) wskazywało we właściwe miejsce? Dzięki temu nie będę musiał przekazywać wyników obliczeń z obiektu do obiektu - same się będą przekazywały
P-134229
RazzorFlame
» 2015-07-01 21:42:28
Problem polega na tym, że przy obecnej konfiguracji w momencie wywołania konstruktora matTransformParent wskazuje co trzeba (sprawdziłem w debuggerze), ale gdy wywoływana jest funkcja Transform matTransformParent wskazuje już jakieś losowe miejsce.
Losowe? Przy niepoprawnym wskaźniku miałbyś crasha na obecnych systemach. Jeżeli wskaźnik jest poprawny to znaczy, że gdzieś po drodze zmieniasz miejsce. Poza tym chciałbym się przyczepić do tego:
matTransform = matRotateX * matRotateY * matRotateZ * matTranslate * matHOOK * * matTransformParent
a dokładniej:
matHOOK * * matTransformParent
Czy nie czytelniej byłoby
matHOOK *( * matTransformParent ) )
 + na przyszłość bezpieczniej?

Teraz przykład jak powinieneś się za to wziąć:
C/C++
class Model
{
public:
    // Bla bla
};
class SceneActor
{
    Model * ModelAsset;
public:
    SceneActor * Parent;
   
    inline Matrix GetTransformationNoScale() { return Matrix( Matrix::Rotation( ActorRot ) * Matrix::Location( ActorLoc ) ); }
    inline Matrix GetTransformation() { return Matrix( Matrix::Scaling( ActorScaling ) * Matrix::Rotation( ActorRot ) * Matrix::Location( ActorLoc ) ); }
    inline Matrix GetTransformationAttachedToParent()
    {
        if( Parent )
        {
            return Matrix( Parent->GetTransformationNoScale() * GetTransformation() );
        }
        else
             return GetTransformation();
       
    }
};

class ActorRegister
{
public:
    std::vector < SceneActor *> Actors;
};

int main()
{
    ActorRegister MyActorRegister;
    SceneActor * someActor = new SceneActor();
    SceneActor * attachedActor = new SceneActor();
    attachedActor->Parent = someActor;
    MyActorRegister.Actors.push_back( someActor );
    MyActorRegister.Actors.push_back( attachedActor );
}
W tym przypadku to wszystko zadziała. Napisałem przykład bo nie wiem co u siebie "po drodze" robisz. Po prostu - jeżeli masz poprawny wskaźnik to wszystko powinno działać.
Radzę też zamiast trzymania samej transformacji aktora "rodzica" trzymać cały wskaźnik na rodzica
P-134232
qrchack
Temat założony przez niniejszego użytkownika
» 2015-07-01 22:13:39
Dzięki Ci wielkie!
Będę próbował :]

Dam znać co mi wyszło, jeśli wyjdzie :]
Ad (...) * o * * p
Przywykłem do przyklejania * do wskaźnika, a mnożenia mam zawsze "luzem" więc ja tam i tak wiem o co chodzi ;] Ale co fakt, to fakt - tak jest na pewno bezpieczniej. Czy czytelniej to już chyba kwestia gustu

Ad reszta kodu
To je openGl? Kolega siedzi w temacie?

P-134234
qrchack
Temat założony przez niniejszego użytkownika
» 2015-07-02 00:44:59
Już pojąłem co się działo w trakcie działania mojego programu...

Pozwolę sobie zostawić w orginale:
The comment that I wanted to add, is that if you do an insertion or a deletion on the vector, which could cause the vector to reallocate it's memory, then you will cause all of your saved pointers and iterators to be invalidated.

(Ty ewidentnie nie potrzebujesz tłumaczenia, ale dla ewentualnych zagubionych (jak ja)...)
Czyli, jeśli zmodyfikujesz rozmiar wektora, czego wynikiem będzie konieczność przeniesienia w inne miejsce pamięci, wszystkie wskaźniki przestaną być poprawne.

A tak się przecież działo.
Najpierw tworzyłem jeden obiekt, potem drugi i kolejne, a jak w konstruktorze umieściłem wskaźnik na składową, to po zmianie rozmiaru i realoakcji pamięci, siłą rzeczy wskaźnik wskazywał w złe miejsce.

Dobrze rozumiem?
P-134240
RazzorFlame
» 2015-07-02 12:25:39
Tak, teraz dobrze to rozumiesz.
To je openGl?
To po prostu jest przykład, będzie działać na DirectX, OpenGL jak i innych bibliotekach jeżeli dobrze zaimplementujesz te klasy. To nie jest fragment mojego kodu ale to taki przykład. Wzorowałem się na hierarchii Unreal Engine 4. Mogę Ci dać radę - model powinien być inną klasą niż obiekt na scenie, bo przecież np. na scenie możesz mieć 15 beczek i nie potrzeba wczytywać 15x tej samej beczki.
P-134246
qrchack
Temat założony przez niniejszego użytkownika
» 2015-07-03 11:17:55
Nie umiem cytować na forum :(

@Nie ma sensu ładować tej samej beczki:
Ponieważ z dxem i 3d jako takim dopiero przygodę zaczynam, pewnie wszystko robię fundamentalnie źle ;]

Anyway: Zgrubsza pisząc u mnie to wygląda tak:
Mam klasę
C/C++
class cGlowna
{
private:
    //ponizej sa wektory obiektow roznych typow
    std::vector < cObiekt > tObiekty;
   
public:
    void przesun_obiekty( void );
    void sprawdz_interakcje( void );
    void rysuj( void );
};

Obiekty cObiekt mają w sobie obiekty cModel które razem tworzą hierarchiczną strukturę, więc ręce animują mi sie prawidłowo względem tułowia. I po to mi był ten nieszczęsny wskaźnik od którego zacząłem temat ;]

Sugerujesz, że lepiej by było, gdyby wektor z modelami był w cGlowna, w cGlowna by sie tworzyly "fizyczne" obiekty w pamieci, a w cObiekt tylko pointerować do już gotowych modeli?

Problem polega na tym, że ja nie wiem z góry, jaki obiekt będzie mi potrzebny - to się okazuje dopiero na etapie powstawania obiektu cObiekt. Plan jest taki, żeby cały świat, wrogowie itd był tworzony proceduralnie i nie wiem, czy props który właśnie kazałem stworzyć w klasie cGlowna bedzie beczką, kawałkiem skały, rozwalonym samochodem, drzewem czy whatever - to się okażę dopiero po obliczeniu parametrow obiektu na podstawie pozycji
P-134271
« 1 » 2
  Strona 1 z 2 Następna strona