[C++, biblioteki] length() w konstruktorze

0

Hej, jestem początkująca w programowaniu także proszę o wyrozumiałość i opisywanie w miarę prostym językiem, dzięki z góry :D

Pisząc bibliotekę, przy użyciu funkcji length w konstruktorze zapamiętuje ona rozmiar "pierwotnego" napisu i jedynie dopisuje rozmiar tego właściwego.

konstruktor w strukturze, w pliku o rozszerzeniu .h: Osoba(string I="", string N="", string P="", int W=1);
wywołanie w programie testującym: ktos=Osoba ("Jan", "Nowak", "00301309169", 178);

Problem pojawił się przy próbach uzyskania komunikatu o błędzie za pomocą throw invalid_argument kiedy pesel jest długości innej niż 11 znaków. Wyświetliłam sobie wartosć jaką dla rzeczonego peselu przyjmuje length() i otrzymałam jego faktyczną długość poprzedzoną (w przypadku powyższego kodu) zerem. Zero zmieniało się na inne wartości, w zależności od ilości spacji. Oczywiście rozmiar imienia też wynosił 03, nazwiska 05 itd.
Jak w inny sposób zadeklarować napis pusty, aby to ominąć lub pozbyć się tego pierwotnego rozmiaru z tego co zwraca funkcja length?

Kod źródłowy:
bib_osoby.h

struct Osoba
{
    string imie;
    string nazwisko;
    int pesel[11];
    int wzrost;
    void wypisz();
 
    Osoba(string I="", string N="", string P="", int W=1);
};

test.cpp

#include "bib_osoby.h"
#include <iostream>
using namespace std;
int main ()
{
    Osoba ktos;
    ktos=Osoba ("Jan", "Nowak", "00301309169", 178);
    ktos.wypisz();
    return 0;
}

konstruktor z bib_osoby.cpp

Osoba::Osoba(string I, string N, string P, int W)
{
    imie=I, nazwisko=N;
    if (W>0)
        wzrost=W;
    else throw invalid_argument ("niepoprawny wzrost");
    if (P.length()!=11) throw invalid_argument ("niepoprawna dlugosc peselu");
cout << P.length();
    for(int i=0;i<11;i++)
    {
        if(P[i]<'0'||P[i]>'9')
            throw ("niepoprawna liczba w peselu");
        else
            pesel[i]=P[i]-'0';
    }

}

1

Wywalanie wyjąku w konsruktorze to zawsze wątpliwe podejscie.
W przypadku błedu zwyczajnie ustaw pesel na pusty, i wywalaj wyjątek przy próbie użycia

0

Czytałem opis kilka razy, ale nie rozumiem w czym jest problem. Mam natomiast kilka uwag:

    Osoba ktos;
    ktos=Osoba ("Jan", "Nowak", "00301309169", 178);

zamiast tego:

    Osoba ktos("Jan", "Nowak", "00301309169", 178);
if(P[i]<'0'||P[i]>'9')

użyj isdigit()

throw ("niepoprawna liczba w peselu");

rzuć klasę dziedziczącą po std::exception a nie char const*

Ogółem, nie należy bezpośrednio używać klas wyjątków z biblioteki standardowej, tylko po nich dziedziczyć własne. Ale na potrzeby przykładowego zadania nie jest to wielkim problemem.

0

Cały kod:

bib_osoby.cpp

#include "bib_osoby.h"
#include <iostream>
//#include <stdexcept>
using namespace std;

//konstruktory
Osoba::Osoba(string I, string N, string P, int W)
{
    imie=I, nazwisko=N;
    if (W>0)
        wzrost=W;
    else throw invalid_argument ("niepoprawny wzrost");
    if (P.length()!=11) throw invalid_argument ("niepoprawna dlugosc peselu");
cout << P.length();
    for(int i=0;i<11;i++)
    {
        if(isdigit(P[i])==false)
            throw invalid_argument("niepoprawna liczba w peselu");
        else
            pesel[i]=P[i]-'0';
    }

}






//funkcje osoby
void Osoba::wypisz()
{
    cout << imie << " " << nazwisko << endl;
    cout << wzrost << " cm" << endl;
    cout << "PESEL: ";
    for (int i=0;i<11;i++)
    {
        cout << pesel[i];
    }
    cout << endl;
}
void Osoba::zmienwzrost()
{
    cout << "Podaj nowy wzrost: ";
    cin >> wzrost;
}
void Osoba::zmiennazwisko()
{
    cout << "Podaj nowe nazwisko: ";
    cin >> nazwisko;
}
bool Osoba::czykobieta()
{
    if (pesel[8]%2==0) return true;
    else return false;

}
bool Osoba::czymezczyzna()
{
    if (pesel[8]%2==1) return true;
    else return false;

}
int Osoba::rok()
{
    if (pesel[2]>1) return 2000+10*(pesel[0])+(pesel[1]);
    else return 1900+10*(pesel[0])+(pesel[1]);
}
int Osoba::miesiac()
{
    if (pesel[2]>1) return (pesel[2]-2)*10+pesel[3];
    else return (pesel[2])*10+(pesel[3]);
}
int Osoba::dzien()
{
    if (pesel[4]==0) return pesel[5];
    else return (pesel[4])*10+(pesel[5]);
}

bib_osoby.h

//tutaj dostepne funkcje i typy
#ifndef ZNAM_BIB_OSOBY
#define ZNAM_BIB_OSOBY
#include <string>
using namespace std;
struct Osoba
{
    string imie;
    string nazwisko;
    int pesel[11];
    int wzrost;
    void wypisz();
    void zmienwzrost();
    void zmiennazwisko();
    bool czykobieta();
    bool czymezczyzna();
    int rok();
    int miesiac();
    int dzien();
    Osoba(string I="", string N="", string P="", int W=1);

};



#endif


testujący

#include "bib_osoby.h"
#include <iostream>
using namespace std;
int main ()
{
    Osoba ktos;
    //Grupa grupa1;

    ktos = Osoba ("Jan", "Nowak", "00301309169", 178);
    ktos.wypisz();
    ktos.zmienwzrost();
    ktos.wypisz();
    ktos.zmiennazwisko();
    ktos.wypisz();
    cout << "K: " << ktos.czykobieta() << endl;
    cout << "M: "<< ktos.czymezczyzna()<< endl;
    cout << "Data ur.: " << ktos.dzien() << "." << ktos.miesiac() << "." << ktos.rok();

    return 0;
}


0

W C++ jest try catch, może spróbować takiego "dizajnu"?

0

@Martyna Michalska: Jak się okazuje wystarczyło się zastosować do moich sugestii.

    Osoba ktos; // tu tworzysz osobę z defaultowymi danymi, czyli pustym peselem ⟶ rzucasz wyjątek
    //Grupa grupa1;

    ktos = Osoba ("Jan", "Nowak", "00301309169", 178); // tutaj nadpisujesz

To nie ma sensu, zastosuj się do mojej rady wyżej.

1
  1. Deklaracja
    int pesel[11];
    jest przynajmniej dziwna, dlaczego int, i dlaczego nie char, albo string
    Sam sobie odpowiadam: bo nie utrwaliłaś sobie (na gruncie matematyki) czym jest cyfra, a czym jest liczba (odsyłam do np wikipedii)
    throw ("niepoprawna liczba w peselu");

  2. Dziwne to zadanie ... a jak Słowak, Ukrainiec nie ma peselu, to nie jest Osobą?

  3. jest 11 to funkcja podaje rozmiar 011, wygląda to jakby zapamiętywała niepotrzebnie rozmiar pustego stringa - Martyna Michalska
    Obstawiam, że błędnie to analizujesz. Nie ma możliwości zwrócenia liczby 011. Prawdopodobnie nakłada CI się podczas drukowania

3a. Unikaj drukowania na cout w wewnętrznych częściach kodu (jest to do wybaczenia w kodzie początkujących), za to naucz się używać debugera

1

Weż zrób sobie osobą klasę na PESEL

0

Siłą C++ jest m.in system typów i nie wiem czemu tak rzadko jest wykorzystywany.
Pesel wymaga walidacji? -> napisz klasę która o to zadba i użyj jej jako argumentu zamiast zwykłego string
Wzrost musi być dodatni? -> Napisz klasę która o to zadba i użyj jej jako argumentu zamiast zwykłego int

Takie podejście dodatkowo umożliwi stworzenie w danej klasie statycznej metody typu bool pesel::is_valid(string const& str)

BTW widzę lekką niekonsekwencję. Można odnieść wrażenie, że wzrost jest ważniejszy od nazwiska czy imienia :P

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