c++ i wskazniki

amenoth
Użytkownik
Użytkownik
Posty: 3
Rejestracja: 22 mar 2011, o 15:51
Płeć: Mężczyzna
Lokalizacja: Kraków

c++ i wskazniki

Post autor: amenoth »

Z zakresu c++ mam blade pojęcie, dlatego proszę o nie ganienie mnie za to, czy za tamto, ale dobre rady, chętnie przyjmę.
Co do kodu, to miała to być taka tam klasa, a właściwie lista dwukierunkowa - kwestia podejścia do tematu. Pchnęła mnie do tego chęć eksperymentowania, bo jak wiadomo powszechnie, tak się można najszybciej nauczyć. Jednak po napisaniu tego pojawił się dziwny problem.
Funkcja repair() nie robi tego co powinna w zakresie zmiany wskaźnika dla pierwszej osoby, natomiast dla drugiej jest ok.

Moje pytania:
- czemu tak się dzieje, że tylko dla pierwszej osoby tak jest
- co robię źle(tutaj ogólnie)
- co polecacie(jak to poprawić)

EDIT: Teraz jak to zamieściłem, to już wiem gdzie jest błąd. Operuję na wskaźniku do obiektu, który chcę zmienić:

Kod: Zaznacz cały

 this->repair(&a,a.getNext());
Teraz się zastanawiam jak to ominąć =]. Ale komentarzy chętnie wysłucham ;P

EDIT2: Hmm przez te chwilę zdążyłem coś wymyślić, co działa(sprawdziłem dla 4 elementów ;P).
Wiem, że to dziwnie wygląda tak okrężnie się odwoływać, ale adres bitowy &a i *a(i do tego też jakby ktoś mnie oświecił ^^) był inny, więc też musiałem przyrównać to do wskaźnika i wybrałem przez następny obiekt. Domyślam się, iż jest na to lepszy sposób, ale obecnie mi nic nie przychodzi do głowy, a i inne rzeczy czekają .

Proszę o jakiś komentarz do zmiany i również radę ;p
tutaj zmiana repair():

Kod: Zaznacz cały

void repair(person *a, person *b){
            this->setNext(b);
            this->setPrev(a);
            if(a==b){
                b->setNext(this);
                b->setPrev(this);
            }       
            else if(a!=b){
                a->setNext(this);
                b->setPrev(this);
            }    
        }    
a tu zmiana konstruktora:

Kod: Zaznacz cały

person(string name,double height,person a){
            this->name = name;
            this->height = height;
            prev=this;
            next=this;
            repair(a.getNext()->getPrev(),a.getNext());   
        }       

A tu kod całości:

Kod: Zaznacz cały

#include <iostream>
#include <conio.h>

using namespace std;

class person{
    private:
        string name;
        double height;
        person *next;
        person *prev;
         
        void repair(person *a, person *b){
                a->setNext(this);
                b->setPrev(this);
                this->setPrev(a);
                this->setNext(b);
        }    
        
        void setNext(person *b){
            next = b;
        }    
        
        void setPrev(person *a){
            prev = a;
        }    
        
    public:
        
        person(string name,double height){
            this->name = name;
            this->height = height;
            prev = this;
            next = this;
        }
        
        person(string name,double height,person a){
            this->name = name;
            this->height = height;
            prev=this;
            next=this;
            this->repair(&a,a.getNext());
            
        }        
        
        person *getNext(){
            return next;
        }    
        
        person *getPrev(){
            return prev;
        }    
        
        string getName(){
            return name;
        }  
        
        double getHeight(){
            return height;
        }     
        
        void drukuj(){
            if(this!=NULL){
                cout << "Imie: " << this->getName() << "	" << "Wzrost: " << this->getHeight() << endl;
            }    
        }    
        
};    


int main(){
    person a("Adam",184);
    person b("Ewa",190,a);
    a.getNext()->drukuj();
    
    getch();
    return 0;
}    
Crizz
Użytkownik
Użytkownik
Posty: 4094
Rejestracja: 10 lut 2008, o 15:31
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 12 razy
Pomógł: 805 razy

c++ i wskazniki

Post autor: Crizz »

Hmmm...

...używałes może wcześniej innych języków programowania w stylu Java, C# itp.?

Kilka uwag:

Kod: Zaznacz cały

void drukuj(){
            if(this!=NULL){
                cout << "Imie: " << this->getName() << "	" << "Wzrost: " << this->getHeight() << endl;
            }
Warunek nie ma szansy być niespełniony, bo na rzecz nieistniejącego obiektu w ogóle nie można wywołać funkcji drukuj.

Kod: Zaznacz cały

person(string name,double height,person a){
            this->name = name;
            this->height = height;
            prev=this;
            next=this;
            this->repair(&a,a.getNext());
            
        }
No i tutaj...

...czemu próbujesz przekazać jako argument obiekt klasy person? Ogólnie to zdajesz sobie sprawę, że obiekty a i b w funkcji main utworzyłeś na stosie? Jeśli Twoja lista ma być dynamicznym typem danych, to wtedy wypadałoby przekazać jako parametr wskaźnik do person, albo odebrać person a jako referencję. Tu natomiast popełniasz bardzo poważny błąd, który polega na tym, że:
tworzysz na stosie kopię obiektu a typu Person (na potrzeby konstruktora, jako argument wywołania)
przekazujesz adres kopii do funkcji repair
wewnątrz funkcji mówisz kopii, że ma nowy kolejny element, a nowemu elementowi, że ma jako poprzedni element kopię obiektu a
po zakończeniu konstruktora kopia obiektu a jest niszczona
amenoth
Użytkownik
Użytkownik
Posty: 3
Rejestracja: 22 mar 2011, o 15:51
Płeć: Mężczyzna
Lokalizacja: Kraków

c++ i wskazniki

Post autor: amenoth »

Bogu dzięki, że ktoś raczył mi odpowiedzieć xd

No tam trochę pisałem w javie. Przewertowałem prawie całą książkę horstmanna Java:Podstawy wyd. VIII, z wyjątkiem refleksji, a końcowe 100 stron to już tylko tak informacyjnie poczytałem, bo byłem bardzo zmęczony pogonią(z własnej woli =p). Mam jeszcze część Java: Zaawansowane(czy jakoś tak) i grafikę w javie xd. Nie uważam jednak, żebym był w niej dobry xd. Natomiast dużą radochę mi sprawiało redefiniowanie klas i metod z bibliotek oraz eksperymentowanie z dziedziczeniem xd
Generalnie bardzo przyjemny język ;p

Bardzo dziękuję, za oświecenie mnie z tym przekazywaniem kopii obiektu =] Z pewnością później, jak już wrócę z zajęć, to się zabiorę za poprawianie.

(co do drukuj, to wiem o tym, ale wcześniejsza wersja tego kodu, tego wymagała, nie pytaj dlaczego, teraz już wiem, gdzie okazałem się debilem ;p)

Mam jeszcze wiele ofc pytań, ale tak na teraz, to jeszcze się zastanowię nad tym wszystkim i jak tylko znajdę czas, to napiszę, co mnie ciekawi =]

EDIT:
a to z tą funkcją drukuj(), to dlatego, że wcześniej tam była tablica z NULL'ami i wtedy był crash ;p

-- 24 mar 2011, o 21:21 --

Jako, że nie chcę się chwalić swoim beznadziejnym kodem, to wolę operować tak na czysto ;p
Chciałbym utworzyć klasę, która będzie tablicą wskaźników do obiektów innej klasy.
-czy zapis w polu :

Kod: Zaznacz cały

person *tab[];
...
a potem w konstruktorze:

Kod: Zaznacz cały

lista(int n){
        *tab = tab[n];
}
jest poprawny ? Jeśli nie, to jak to zmienić =P
- gdy wywołuję metodę:

Kod: Zaznacz cały

void add(enemy *a){
        tab[6] = a;/*to tylko taki przykład xd*/
}
to kompilator mówi mi:
request for member `add' in ` lista()', which is of non-aggregate type `listek ()()'

Od razu powiem, że to nie jest tak, że jak czegoś nie wiem to na forum lecę. Nigdy nie lubię sięgać po czyjąś pomoc i wolałbym sam odnaleźć odpowiedź ale zmęczony już nieco jestem(i zniecierpliwiony).
Awatar użytkownika
kadiii
Użytkownik
Użytkownik
Posty: 642
Rejestracja: 20 gru 2005, o 21:04
Płeć: Mężczyzna
Lokalizacja: Wrocław
Pomógł: 130 razy

c++ i wskazniki

Post autor: kadiii »

-czy zapis w polu: ... jest poprawny?
Muszę cię zmartwić - nie jest poprawny.
To co próbujesz wykonać to dynamiczna alokacja tablicy dwuwymiarowej. Ale do rzeczy:
Bierzemy sobie naszą niezainicjalizowaną tablicę wskaźników i deklarujemy ją w formie wskaźnikowej:

Kod: Zaznacz cały

person **tab;
Na razie oznacza to jedynie, że mamy niepokazujący na nic zbiór iluś tam wskaźników - powiedzmy pustą kartkę, na której może coś zapiszemy. No to zapiszmy ile chcemy osób na liście:

Kod: Zaznacz cały

lista(int n){
 tab = new person*[n];
}
No to mamy już na naszej kartce tabelkę dla n osób, można już śmiało zapisywać konkretne osoby,
Tak:

Kod: Zaznacz cały

person p1("john",180);
person *pt = &p1;
lista.tab[0] = pt;
lub tak:

Kod: Zaznacz cały

lista.tab[0] = new person("john",180);
To tak na tyle odnośnie tego kawałka kodu. Teraz parę uwag natury ogólnej:
- nazwy klas zwyczajowo pisze się z dużej litery
- jak piszesz kod to się zdecyduj - polski czy angielski - nie mieszaj obu!
- jak chcesz pomocy przy kodzie to go wklej w całości(chyba, że akurat odnosisz się tylko do linijki kodu), to, że napiszesz coś niepoprawnie nie świadczy w żadnym stopniu o twoim poziomie inteligencji - przecież dopiero się uczysz.
Pozdrawiam
amenoth
Użytkownik
Użytkownik
Posty: 3
Rejestracja: 22 mar 2011, o 15:51
Płeć: Mężczyzna
Lokalizacja: Kraków

c++ i wskazniki

Post autor: amenoth »

Bez obaw, nie zwykłem mieszać ang i pol ;p Normalnie jak w javie pisałem lub też teraz w c++, to wszystko w ang, bo tak mi wygodniej =p - to tylko był taki mój przykład, bo jak chcę coś sprawdzić/policzyć, to tak na szybko często nadaję nazwy, które mi przyjdą pierwsze do głowy, bo i tak zaraz potem kod zostanie wywalony, lub też zatrzymany do zapamiętania ;p). Co zaś się tyczy klas, to już odwykłem od pisania i może to mnie gubi, bo w javie, o ile mnie pamięć nie myli miałem wszystkie z dużej ;p

Co do dodawania osób do tablicy wskaźników, to tyle umiem ;p. Zasadniczo jakieś podstawy przyswoiłem z "Od zera do gier kodera", tzn tam pierwsze ~160str, to wszystko, a potem to co mnie interesowało(czyt. ciekawiło =]).
ODPOWIEDZ