Pokaż wyniki 1 do 8 z 8

Temat: [c++] odwolywanie sie do innej klasy

  1. #1
    Zarejestrowany
    Mar 2013
    Postów
    6

    Domyślnie [c++] odwolywanie sie do innej klasy

    Witajcie!
    Rozpoczęłam naukę programowania obiektowego w C++ i pojawił mi sie problem.

    Stworzyłam następujące klasy:
    Kod:
    #include <iostream>
    using namespace std;
    
    
    class Dzialania
    {
            private:
                    int x,y;
                    double z1,z2;
            public:
                    Dzialania(int,int);
                    void dzial();
    };
    
    
    Dzialania::Dzialania(int a,int b)
    {
            x=a;
            y=b;
    }
    
    void Dzialania::dzial()
    {
            z1=x*y;
            z2=x/y;
    
            cout<<"z1 = "<<z1<<"\n";
            cout<<"z2 = "<<z2<<"\n";
    }
    class Prostokat
    {
           private:
                   int x,y;
           public:
                   Prostokat(double, double); 
                   double pole(void) {return x*y;}
    };
    
    Prostokat:: Prostokat(double a,double b)
    {
        x=a;
        y=b;
    }
    
    int main()
    {
        Dzialania D(10,2);
        D.dzial();
    
        Prostokat a(2,4);
        cout << "Pole prostokata a = " << a.pole() << '\n';
    Jednakże chciałabym wykorzystać z1 i z2 z klasy Dzialania i wstawić do klasy Prostokat.
    Tak aby pole prostokata bylo liczone: z1*z2.
    Czy w takiej sytuacji powinnam użyc wskazników? Czy sa do tego inne ticky?

  2. #2
    Zarejestrowany
    Jan 2008
    Skąd
    za NATem :)
    Postów
    155

    Domyślnie

    Programowanie obiektowe nie polega na użyciu słowa class.
    Obiekt posiada swój stan wewnętrzny (opisywany przez jego pola) oraz wykonuje pewne czynności (metody).
    Języki takie jak C++ posiadają konstrukcje ułatwiające ten sposób programowania, jednak obiektowo można pisać praktycznie w każdym języku, bo obiektowość to sposób rozumienia programu a nie jego zapisu.
    Do poczytania http://xion.org.pl/productions/texts.../megatutorial/ (rozdziały 1.5-1.7 i 2.2, ale jak przeczytasz całość to nie zaszkodzi) i http://pl.wikipedia.org/wiki/Hermetyzacja_(informatyka).

    Jeśli jakiś obiekt potrzebuje innego obiektu to może go np. zawierać, opcjonalnie może zawierać wskaźnik/referencję do niego jeśli jest to obiekt polimorficzny lub jest używany przez kilka obiektów. Jeśli obiekt nie potrzebuje innego obiektu cały czas, a jedynie do wykonania jakiejś operacji potrzebuje obiektu określonej klasy, to może sobie taki obiekt stworzyć na tylko na czas wykonywania tej operacji.
    Jeśli ma to sens to określone klasy mogą dziedziczyć jedna z drugiej (w ogóle w programowaniu sensowność jest bardzo ważna).

    Pola z1 i z2 klasy Dzialania są prywatne, żeby móc z nich skorzystać poza klasą Dzialania powinnaś udostepnić jakiś sposób dostępu do nich, np. stworzyć metody do odczytu ich wartości.
    Niniejszy post przedstawia opinie autora w dniu dzisiejszym, na datę jego publikacji. Nie mogą być one wykorzystane przeciwko niemu w dniu jutrzejszym, ani innym następującym po nim dniu. Autor zastrzega sobie prawo do zmiany poglądów bez podawania przyczyn.

  3. #3
    Zarejestrowany
    Mar 2013
    Postów
    6

    Domyślnie

    Wykorzystalam dziedziczenie klas i stworzyłam coś takiego:
    Kod:
    #include <iostream>
    using namespace std;
    
    
    
    class Dzialania
    {
            private:
                    int x,y;
                    double z1,z2;
            public:
                    Dzialania(int,int);
                    void dzial();
    
                    double Z1() {return z1;}
                    double Z2() {return z2;}
    };
    
    
    Dzialania::Dzialania(int a=1,int b=2)  //Czy tutaj muszę podawać wartości początkowe? Niestety bez tego wyrzuca mi error
    
    {
            x=a;
            y=b;
    }
    
    void Dzialania::dzial()
    {
            z1=x*y;
            z2=x+y;
    
            cout<<"z1 = "<<z1<<"\n";
            cout<<"z2 = "<<z2<<"\n";
    }
    
    
    class Prostokat: public Dzialania
    {
            private:
                    int m,n;
            public:
                    Prostokat(int, int);
                     double pole() {return m*Z1()*n*Z2();}
    };
    
    Prostokat:: Prostokat(int a,int b)
    {
        m=a;
        n=b;
    }
    
    
    int main()
    {
        Prostokat a(2,2);
        cout << "Pole prostokata a = " << a.pole() << '\n';
    
        Dzialania D;
        D.dzial();
    }
    Jednakże za pole prostokąta wyrzucane są jakieś śmieci. Niestety nie wiem dlaczego tak się dzieje.
    Czy w ogóle taki sposób jest dobry, by rozwiązać ten problem?
    Ostatnio edytowane przez Mona : 03-24-2013 - 21:18

  4. #4
    Zarejestrowany
    Jan 2008
    Skąd
    za NATem :)
    Postów
    155

    Post

    "Prostokat jest rodzajem Dzialania."

    Cytat Napisał Mona Zobacz post
    Kod:
    Dzialania::Dzialania(int a=1,int b=2)  //Czy tutaj muszę podawać wartości początkowe? Niestety bez tego wyrzuca mi error
    Jeśli na liście inicjalizacyjnej konstruktora klasy pochodnej nie podasz z jakimi argumentami ma być wywołany konstruktor klasy bazowej, to domyślnie jest wywoływany konstruktor domyślny, czyli taki, który nie przyjmuje żadnych argumentów.
    Trywialny konstruktor domyślny jest tworzony niejawnie tylko wtedy gdy nie zdefiniujesz żadnego innego.
    Jeśli wszystkim argumentom jakiegoś konstruktora ustawisz wartości domyślne to może być on wtedy używany jako konstruktor domyślny, bo może być wywołany bez podawania argumentów.

    Cytat Napisał Mona Zobacz post
    Jednakże za pole prostokąta wyrzucane są jakieś śmieci.
    Do obliczenia twojego "pola" używasz z1 i z2, którym nie zostały przypisane żadne wartości, więc zawierają śmieci.
    coś * śmieć * coś * śmieć = śmieć
    Metoda dzial() ustawia tym zmiennym "poprawne" wartości. Jeśli wywołasz ją przed pole() to otrzymasz nieśmieciową wartość.
    Kod:
    Prostokat a(2,2);
    a.dzial();
    cout << "Pole prostokata a = " << a.pole() << '\n';
    Jednakże poprawność obiektu nie powinna zależeć od kolejności wywoływania jego metod. Po zakończeniu działania konstruktora wszystkie pola obiektu powinny mieć ustawione poprawne wartości.

    Cytat Napisał Mona Zobacz post
    Czy w ogóle taki sposób jest dobry, by rozwiązać ten problem?
    Jaki problem? Nie napisałaś czemu ten program ma służyć.
    Podałaś tylko problem implementacyjny. Czasem wprowadza się poprawki do modelu obiektowego ze względu na trudności implementacyjne, ale powinny to być zmiany sensowne.
    Niniejszy post przedstawia opinie autora w dniu dzisiejszym, na datę jego publikacji. Nie mogą być one wykorzystane przeciwko niemu w dniu jutrzejszym, ani innym następującym po nim dniu. Autor zastrzega sobie prawo do zmiany poglądów bez podawania przyczyn.

  5. #5
    Zarejestrowany
    Mar 2013
    Postów
    6

    Domyślnie

    Cytat Napisał Rolek Zobacz post
    "Prostokat jest rodzajem Dzialania."

    Jeśli na liście inicjalizacyjnej konstruktora klasy pochodnej nie podasz z jakimi argumentami ma być wywołany konstruktor klasy bazowej, to domyślnie jest wywoływany konstruktor domyślny, czyli taki, który nie przyjmuje żadnych argumentów.
    Trywialny konstruktor domyślny jest tworzony niejawnie tylko wtedy gdy nie zdefiniujesz żadnego innego.
    Jeśli wszystkim argumentom jakiegoś konstruktora ustawisz wartości domyślne to może być on wtedy używany jako konstruktor domyślny, bo może być wywołany bez podawania argumentów.
    ok, ale nadal nie rozumiem dlaczego w tym przykadzie musze od razu podac te wartosci w funkcji: Dzialania(int a=3,int b=2), a nie moge wywolac konstruktora z poczatkowymi wartosciami w funkcji main.

    Jaki problem? Nie napisałaś czemu ten program ma służyć.
    Podałaś tylko problem implementacyjny. Czasem wprowadza się poprawki do modelu obiektowego ze względu na trudności implementacyjne, ale powinny to być zmiany sensowne.
    Dopiero zaczynam naukę i nie mam jeszcze pomysłu na stworzenie jakiegoś projektu, stąd take dziwne przykłady.


    Probowalam to jeszcze zrobic bez dziedziczenia klasy w taki sposob:
    Kod:
    #include <iostream>
    using namespace std;
    
    class Dzialania
    {
            private:
                    int x,y;
                    double z1,z2;
            public:
                    Dzialania(int,int);
                    void dzial();
    
                    double Z1() {return z1;}
                    double Z2() {return z2;}
    };
    
    
    Dzialania::Dzialania(int a,int b)
    {
            x=a;
            y=b;
    }
    
    void Dzialania::dzial()
    {
            z1=x*y;
            z2=x+y;
    
            cout<<"z1 = "<<z1<<"\n";
            cout<<"z2 = "<<z2<<"\n";
    }
    
    
    class Prostokat                 
    {
            private:
                    int m,n;
            public:
     Prostokat(int, int);
                     int pole() {return Dzialania(m,n).Z1()*Dzialania(m,n).Z2();}
    };
    
    Prostokat:: Prostokat(int a,int b)
    {
        m=a;
        n=b;
    }
    
    
    int main()
    {
    
            Dzialania D(2,3);
            D.dzial();
            cout<<"sprawdzam "<<D.Z1()<<endl;;
    
    
            Prostokat a(2,2);
            cout << "Pole prostokata a = " << a.pole() << '\n';
    
    }
    Tak jak wcześniej napisałes Z1 i Z2 nic nie zwraca, więc nie ma opcji, by to działało poprawnie. Gdzieś trzeba wywolac funkcje dzial() z klasy Dzialania.

  6. #6
    Zarejestrowany
    Jan 2008
    Skąd
    za NATem :)
    Postów
    155

    Domyślnie

    Cytat Napisał Mona Zobacz post
    ok, ale nadal nie rozumiem dlaczego w tym przykadzie musze od razu podac te wartosci w funkcji: Dzialania(int a=3,int b=2), a nie moge wywolac konstruktora z poczatkowymi wartosciami w funkcji main.
    W C++ nie ma ręcznego składania obiektów, obiekt jest tworzony w całości przez konstruktor, jeśli wywołujesz konstruktor typu pochodnego to on wywołuje konstruktor odpowiedniego typu bazowego.
    Możesz za pośrednictwem konstruktora klasy pochodnej przekazać argumenty do konstruktora klasy bazowej.
    Kod:
    class A
    {
    public:
    	int m_x;
    	A(int x) : m_x(x) { }
    };
    
    class B : public A
    {
    public:
    	int m_y;
    	B(int x, int y) : A(x), m_y(y) { }
    };
    
    #include <iostream>
    
    int main()
    {
    	B foo(1, 2);
    	std::cout << foo.m_x << " " << foo.m_y;
    	return 0;
    }
    Cytat Napisał Mona Zobacz post
    Tak jak wcześniej napisałes Z1 i Z2 nic nie zwraca, więc nie ma opcji, by to działało poprawnie. Gdzieś trzeba wywolac funkcje dzial() z klasy Dzialania.
    Możesz np.
    Kod:
    int pole()
    {
    	Dzialania d(m, n);
    	d.dzial();
    	return d.Z1() * d.Z2();
    }
    Ale tak jak wspominałem, dobrze by było gdyby cała zawartość obiektu była ustawiana na poprawne wartości przez konstruktor. Oczywiście metody mogą zmieniać zawartość obiektu, jednak nie powinno być wymagane wywoływanie dodatkowych metod w celu "dokończenia" inicjalizacji.
    Niniejszy post przedstawia opinie autora w dniu dzisiejszym, na datę jego publikacji. Nie mogą być one wykorzystane przeciwko niemu w dniu jutrzejszym, ani innym następującym po nim dniu. Autor zastrzega sobie prawo do zmiany poglądów bez podawania przyczyn.

  7. #7
    Zarejestrowany
    Mar 2013
    Postów
    6

    Domyślnie

    Ale tak jak wspominałem, dobrze by było gdyby cała zawartość obiektu była ustawiana na poprawne wartości przez konstruktor. Oczywiście metody mogą zmieniać zawartość obiektu, jednak nie powinno być wymagane wywoływanie dodatkowych metod w celu "dokończenia" inicjalizacji.
    Jeśli dobrze rozumiem to najlepiej byloby gdy konstruktor Dzialania zwracalby od razu z1*z2? Następnie obiekt z tą wartościa możemy w dalszej części programu wykorzystać

  8. #8
    Zarejestrowany
    Jan 2008
    Skąd
    za NATem :)
    Postów
    155

    Wink

    Cytat Napisał Mona Zobacz post
    Jeśli dobrze rozumiem to najlepiej byloby gdy konstruktor Dzialania zwracalby od razu z1*z2?
    Konstruktor nic nie zwraca (ewentualnie w kategoriach filozoficznych można uznać, że zwraca skonstruowany obiekt).
    Konstruktor ma za zadanie zainicjalizować obiekt ustawiając jego polom odpowiednie wartości, ewentualnie może zaalokować dodatkową pamięć lub inne zewnętrzne zasoby jeśli obiekt ich potrzebuje.
    Niniejszy post przedstawia opinie autora w dniu dzisiejszym, na datę jego publikacji. Nie mogą być one wykorzystane przeciwko niemu w dniu jutrzejszym, ani innym następującym po nim dniu. Autor zastrzega sobie prawo do zmiany poglądów bez podawania przyczyn.

Zasady Postowania

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów
  •  
Subskrybuj