Programowanie obiektowe - prośba o sprawdzenie stylu programowania

0

Witam, realizuję na studiach kurs "Programowanie obiektowe"(w C++), w 1 semestrze miałem "Podstawy programowania"(ANSI C), piszę program i chciałbym prosić o analizę programu i stwierdzenie czy program napisany jest prawidłowo (tz czy jest obiektowo). Nie za bardzo rozumiem idee programowania obiektowego (tz nie wiem czy dobrze rozumiem). Mam napisać program który będzie czysto obiektowo, nie wiem czy mój program jest obiektowy czy nie do końca. Programowanie obiektowe rozumiem jako programowanie z użyciem klas i obiektów, lecz obawiam się że w moim programie są elementy programowania strukturalnego. Bardzo bym prosił o sprawdzenie oraz wskazanie gdzie są błędy (co nie pasuje do obiektowego programowania). Oto kod (wszystko działa, do poprawienia jedynie obsługa błędów ale to już później):

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <math.h>

using namespace std;

class Lz {
    public:
    double re;
    double im;
};

//Przeciążenia
Lz operator + (Lz liczba1, Lz liczba2) {
    Lz wynik;
    wynik.re = liczba1.re + liczba2.re;
    wynik.im = liczba1.im + liczba2.im;
    return wynik;
}

Lz operator - (Lz liczba1, Lz liczba2) {
    Lz wynik;
    wynik.re = liczba1.re - liczba2.re;
    wynik.im = liczba1.im - liczba2.im;
    return wynik;
}

bool operator == (Lz liczba1, Lz liczba2) {
    if(liczba1.re == liczba2.re and liczba1.im == liczba2.im) return true;
    else return false;
}

Lz operator * (Lz liczba1, Lz liczba2) {
    Lz wynik;
    wynik.re = (liczba1.re * liczba2.re) - (liczba1.im * liczba2.im);
    wynik.im = (liczba1.re * liczba1.im) + (liczba1.im * liczba2.re);
    return wynik;
}

Lz operator / (Lz liczba1, Lz liczba2) {
    Lz wynik;
    wynik.re = ((liczba1.re * liczba2.re) + (liczba1.im * liczba2.im)) / (pow(liczba2.re,2) + pow(liczba2.im,2));
    wynik.im = ((liczba1.im * liczba2.re) + (liczba1.re * liczba2.im)) / (pow(liczba2.re,2) + pow(liczba2.im,2));
    return wynik;
}

//przeciążenie standardowego wejścia
istream & operator >> (istream &StrmWe, Lz &liczba) {
    if ( !(StrmWe >> liczba.re >> liczba.im) ) return StrmWe;
    if (StrmWe.peek( ) != 'i') { StrmWe.setstate(ios::failbit); }
    return StrmWe.ignore( );
    return StrmWe;
}

//przeciążenie standardowego wyjscia
ostream & operator << (ostream &StrmWy, Lz &liczba) {
    return StrmWy << liczba.re << showpos << liczba.im << "i";
}

class Statystyka {
    public:
        int poprawne;
        int niepoprawne;

        void odp_niepoprawna() { niepoprawne++; }
        void odp_poprawna() { poprawne++; }
        void zeruj() {
            poprawne = 0;
            niepoprawne = 0;
        }
        void wypisz_statystyki() {
            double wynik = (poprawne * 100)/(poprawne + niepoprawne);
            cout << "Ilosc dobrych odpowiedzi: " << poprawne << endl;
            cout << "Ilosc blednych odpowiedzi: " << niepoprawne << endl;
            cout << "Wynik procentowy poprawnych odpowiedzi:    " << fixed << setprecision(1) << wynik << "%" << endl;
        }
};

class Inout {
    public:
        string sciezka;
        fstream plik;

        void otworz_plik(char wybor) {
            if(wybor == 't') sciezka = "test_arytmetyki_zespolonej.txt";
            else cin >> sciezka;

            if(wybor == 't' or wybor == 'p') plik.open(sciezka.c_str(), ios::in);
            else plik.open(sciezka.c_str(), ios::out);
        }

        bool wczytaj_linijke(Lz &liczba1, Lz &liczba2, char &oper) {
            char znak;
            if(plik >> znak and plik >> liczba1 and plik >> znak and plik >> oper and plik >> znak and plik >> liczba2 and plik >> znak) return true;
            else return false;
        }

        bool zapisz_linijke(Lz liczba1, Lz liczba2, char oper) {
            char znak;
            cout << "Wpisz wyrazenie> ";
            if(cin >> znak and znak != '.') {
                cin >> liczba1;
                cin >> znak;
                cin >> znak;
                cin >> oper;
                cin >> liczba2;
                cin >> oper;
                plik << "(" << liczba1 << ")" << oper << "(" << liczba2 << ")" << endl;
                return true;
            }
            else return false;
        }
};

class Test {
    public:
        Statystyka statystyka;
        Inout plik;
        Lz liczba1;
        Lz liczba2;
        Lz wynik;
        char oper;

        void otworz_test(char wybor) {
            statystyka.zeruj();
            plik.otworz_plik(wybor);

            while(plik.wczytaj_linijke(liczba1,liczba2,oper) == true) {
                if(sprawdz_arytmetyke(liczba1, liczba2, oper) == true) statystyka.odp_poprawna();
                else statystyka.odp_niepoprawna();
            }

            cout << "Koniec testu." << endl << endl;
            statystyka.wypisz_statystyki();
            statystyka.zeruj();
        }

        void stworz_test(char wybor) {
            plik.otworz_plik(wybor);
            while(plik.zapisz_linijke(liczba1, liczba2, oper));
            cout << " Tworzenie testu zakonczone" << endl;
        }

    private:
        bool sprawdz_arytmetyke(Lz liczba1, Lz liczba2, char oper) {
            Lz obliczenia;
            cout << "? Podaj wynik operacji: " << "(" << liczba1 << ")" << oper << "(" << liczba2 << ")" << endl;
            cout << "  Twoja odpowiedz: ";
            cin >> wynik;
            switch (oper) {
            case '+':
                obliczenia = liczba1+liczba2;
            break;
            case '-':
                obliczenia = liczba1-liczba2;
            break;
            case '*':
                obliczenia = liczba1*liczba2;
            break;
            case '/':
                obliczenia = liczba1/liczba2;
            break;
            }
            if(wynik == obliczenia) return true;
            else return false;
        }
};

class Menu {
    public:
        char wybor;
        Test test;

        void wyswietl_menu() {
            cout << "t - Uruchom test: test_arytmetyki_zespolonej.txt" << endl;
            cout << "p - Uruchom test z innego pliku" << endl;
            cout << "u - Utworz test" << endl;
            cout << "w - Wyswietl menu" << endl;
            cout << "k - Koniec dzialania program" << endl << endl;
        }

        void wybor_opcji() {
            do {
                cout <<"Twoj wybor (w - menu) ";
                cin >> wybor;
                cout << endl;
                switch(wybor) {
                    case 't':
                        test.otworz_test(wybor);
                    break;
                    case 'p':
                        test.otworz_test(wybor);
                    break;
                    case 'u':
                        test.stworz_test(wybor);
                    break;
                    case 'w':
                        wyswietl_menu();
                    break;
                    case 'k':
                        zakoncz_program();
                    break;
                    default:
                        cout<<"Bledny wybor"<<endl;
                    break;
                }
            } while(wybor != 'k');
        }

        void zakoncz_program() {
            cout << " Koniec dzialania programu." << endl;
        }
};

int main(int argc, char* argv[]) {
    Menu menu;

    menu.wyswietl_menu();
    menu.wybor_opcji();

    return 0;
}

0

Z tego co widzę wszystkie przeciążone operatory tyczą się klasy Lz, dlaczego więc nie "zamknąć ich" w niej?

0

Hmm myślałem że nie można pisać przeciążeń w klasie, tz że przeciążenie nie tyczy się klasy a jest dla całego programu.

0

To byłoby trochę bez sensu jakby język dawał Ci możliwość przeciążania operatorów dla własnych klas ale odbierając jednocześnie własności dla primitywów. Ogólnie ładniej to by wszystko wyglądało gdybyś porozdzielał wszystkie klasy na osobne pliki.

0

Nie czytałem za bardzo tego kodu, więc będzie krótko.
Dlaczego wszystko jest public??!
dlaczego raz inkludujesz tak jak powinieneś inkludować biblioteki C w C++

#include <cstdlib>

A raz nie

#include <math.h>

Klasy najlepiej podzilić na pliku nagłówkowe i źródłowe..
Klasa Menu mogłaby być singletonem.
Co do operatorów, tak jak @several

0

Dlaczego wszystko jest public??!

Nie zwracałem na to uwagi przy pisaniu kodu, jak widać źle zrobiłem, oczywiście do poprawy.

dlaczego raz inkludujesz tak jak powinieneś inkludować biblioteki C w C++

Nie wiedziałem ze jest różnica, poprawione i już będę wiedział, dziękuję za uwagę.

Klasa Menu mogłaby być singletonem.

Nie wiem co to oznacza, nie będę się wgłębiał bo to poza materiał, kiedyś się dowiem to będę stosował :)

Klasy najlepiej podzilić na pliku nagłówkowe i źródłowe..

Próbuje to zrobić lecz mam mały problem, programuje w NetBeans pod Ubuntu, problem z linkowaniem:

 main.cpp:7: undefined reference to `Menu::wyswietl_menu()'
main.cpp:8: undefined reference to `Menu::wybor_opcji()'

main.cpp

#include "Lz.h"
#include "Menu.h"

int main(int argc, char* argv[]) {
    Menu menu;

    menu.wyswietl_menu();
    menu.wybor_opcji();

    return 0;
} 

Menu.cpp

#include <iostream>

#include "Lz.h"
#include "Test.h"

using namespace std;

class Menu {
    public:
        char wybor;
        Test test;

        void wyswietl_menu() {
            cout << "t - Uruchom test: test_arytmetyki_zespolonej.txt" << endl;
            cout << "p - Uruchom test z innego pliku" << endl;
            cout << "u - Utworz test" << endl;
            cout << "w - Wyswietl menu" << endl;
            cout << "k - Koniec dzialania program" << endl << endl;
        }

        void wybor_opcji() {
            do {
                cout <<"Twoj wybor (w - menu) ";
                cin >> wybor;
                cout << endl;
                switch(wybor) {
                    case 't':
                        test.otworz_test(wybor);
                    break;
                    case 'p':
                        test.otworz_test(wybor);
                    break;
                    case 'u':
                        test.stworz_test(wybor);
                    break;
                    case 'w':
                        wyswietl_menu();
                    break;
                    case 'k':
                        zakoncz_program();
                    break;
                    default:
                        cout<<"Bledny wybor"<<endl;
                    break;
                }
            } while(wybor != 'k');
        }

        void zakoncz_program() {
            cout << " Koniec dzialania programu." << endl;
        }
}; 

Menu.h

class Menu {
    public:
        void wyswietl_menu();

        void wybor_opcji();
        
        void zakoncz_program();
}; 

W czym może być problem??

0

nie ładnie, menu.cpp i menu.h to jakaś herezja.

klasa.h

class Klasa {
    void foo();
};

klasa.cpp

#include "klasa.h"

void Klasa::foo(){}
0

Weź podręcznik od C++ do ręki i sprawdź jak powinny wyglądać definicje metod klas.

0

Zainstaluj code::blocks i daj tam file->new->class.
zobacz Sobie jak wyglądają te pliki.

1 użytkowników online, w tym zalogowanych: 0, gości: 1