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

[C++, biblioteki] length() w konstruktorze
Martyna Michalska
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 4 lata
  • Postów:10
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

Kopiuj
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

Kopiuj
#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

Kopiuj
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';
    }

}

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:2 miesiące
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


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
Zobacz pozostałe 8 komentarzy
kq
Uch, to wyjątki są armatami jeśli chodzi o wpływ na wydajność :​P
Martyna Michalska
znaczy właściwie zależy mi tylko na ogarnięciu tego co zwraca funkcja length, nie wiem czemu tak się dzieje i jak to naprawić - na uczelni wyjątek był pokazany dokładnie w ten sposób
_13th_Dragon
Powinnaś normalnie sprawdzić pesel (nie tylko na długość) po czym wpisać powiedzmy wartość pustą jeżeli nie jest poprawny. Dopiero jak będzie potrzeba użyć PESELA to wywalasz wyjątek.
Martyna Michalska
w tym sęk, że w zadaniu nie trzeba go używać :P po prostu ma być zrobiona obsługa błędu z wykorzystaniem std except, po prostu się zastanawiam jak prowadząca na zajęciach wyobrażała sobie, że to będzie działać
_13th_Dragon
Wg mnie nie wyobraza, słyszała o RAII i nic więcej. A może wcale nie słyszała i nawet nie pomyślala jak to używac później. Zrób buildera, który będzie tworzyć klasę Osoba, w klasie Osoba konstruktor prywatny ale zaprzyjazniony z wewnętrzną klasą Buildera. Albo zrób tak glupio jak prowadząca oczekuje.
kq
Moderator C/C++
  • Rejestracja:ponad 11 lat
  • Ostatnio:około godziny
  • Lokalizacja:Szczecin
0

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

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

zamiast tego:

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

użyj isdigit()

Kopiuj
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.


edytowany 1x, ostatnio: kq
Zobacz pozostałe 17 komentarzy
kq
Builder nie jest specjalnie popularny w C++, ale i tak nie widzę za bardzo w jaki sposób stanowi on rozwiązanie problemu - i tak w założeniu nie powinien pozwolić na utworzenie niepoprawnego obiektu. Co do klasy PESEL - zgoda, ale tutaj wracamy do poprzedniego problemu - PESEL powinien weryfikować poprawność przy tworzeniu. Albo za pomocą wyjątku, albo za pomocą funkcji generującej zwracającej optional<PESEL>.
_13th_Dragon
Prywatny konstruktor i metoda statyczna build która wywołuje prywatnego konstruktora dalej wszystko się zgadza z RAII
kq
No tak - ale teraz zupełnie nie rozumiem w czym problem. Prywatny konstruktor to detal implementacyjny, a ogólnym założeniem RAII jest to, że użytkownik klasy tworząc jej obiekt ma gwarancję, że jest to obiekt poprawny. Nie ma znaczenia, czy utworzy ten obiekt za pomocą statycznej funkcji create(), czy też konstruktora. Jak się uda utorzyć to oczekuje, że obiekt będzie poprawny. A jak się nie uda, to tak samo się złapie lub nie złapie wyjątku z A a = make_a(123); jak i z A a(123);
_13th_Dragon
No i będziesz mieć obiekt poprawny jak bulder przydzieli poprzez new nowy obiekt. Natomiast jak zrobisz kalse domyslną to jak nie kręć nie będzie to obiekt strikte poprawny. Już widzę w czym masz problem: A *a=A::make(123); - share_ptr dla mowszego C++
kq
Ale nie zrobisz, bo konstruktor domyślny jest w tym hipotetycznym przykładzie prywatny.
Martyna Michalska
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 4 lata
  • Postów:10
0

Cały kod:

bib_osoby.cpp

Kopiuj
#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

Kopiuj
//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

Kopiuj
#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;
}


lion137
  • Rejestracja:około 8 lat
  • Ostatnio:2 minuty
  • Postów:4884
0

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


_13th_Dragon
Owszem ale nie w metodzie co woła do zycia obiekt Osoba nie poprzez new
lion137
To Panie Premierze, jak żyć?:)
_13th_Dragon
Zależy czyja ... jak powiedziałem wyżej wzorzec projektowy Builder.
lion137
OK, nada się.
kq
Moderator C/C++
  • Rejestracja:ponad 11 lat
  • Ostatnio:około godziny
  • Lokalizacja:Szczecin
0

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

Kopiuj
    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.


Martyna Michalska
Przeogromne dzięki, tak myślałam że może być problem z wywoływaniem konstruktora :D
AK
  • Rejestracja:ponad 6 lat
  • Ostatnio:około 12 godzin
  • Postów:3561
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


Bo C to najlepszy język, każdy uczeń ci to powie
_13th_Dragon
Odnosnie pkt 2 ... W Polsce - nie jest :D
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:2 miesiące
1

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


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
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


"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)