#include <iostream>
// ============================================================
// KLASA CZAS
// Przechowuje czas w postaci godzin, minut i sekund.
// Atrybuty sa prywatne - dostep tylko przez akcesory (enkapsulacja).
// ============================================================
class Czas
{
private:
int godzina;
int minuta;
int sekunda;
// Metoda prywatna - przelicza czas po kazdej zmianie,
// np. 75 sekund zamienia na 1 minute i 15 sekund.
void przeliczCzas();
// Akcesory ustawiajace sa prywatne - uzywamy ich tylko
// wewnatrz klasy. Na zewnatrz dostepne jest tylko ustawCzas().
void ustawgodz(int godz);
void ustawmin(int min);
void ustawsek(int sek);
public:
// Konstruktory przeciazone - mozna utworzyc obiekt Czas
// podajac same sekundy, sekundy+minuty lub pelny czas.
Czas() { ustawCzas(0, 0, 0); }
Czas(int sek) { ustawCzas(0, 0, sek); }
Czas(int sek, int min) { ustawCzas(0, min, sek); }
Czas(int sek, int min, int godz) { ustawCzas(godz, min, sek); }
// Publiczny akcesor ustawiajacy - jedyny sposob ustawienia czasu
// z zewnatrz klasy. Argumenty min i sek maja wartosci domyslne = 0.
void ustawCzas(int godz, int min = 0, int sek = 0);
// Operatory arytmetyczne - umozliwiaja dodawanie obiektow Czas.
Czas& operator+=(Czas& inny);
Czas operator+(Czas& inny);
// Operatory relacyjne - umozliwiaja porownywanie obiektow Czas.
bool operator<(Czas& inny);
bool operator==(Czas& inny);
bool operator!=(Czas& inny);
bool operator>(Czas& inny);
bool operator<=(Czas& inny);
bool operator>=(Czas& inny);
// Publiczne akcesory odczytujace - pozwalaja pobrac wartosci
// prywatnych atrybutow z zewnatrz klasy.
int pobierzgodz();
int pobierzmin();
int pobierzsek();
// Wypisuje czas na ekran w formacie g:m:s
void wypiszczas();
};
// Operator += modyfikuje obiekt w miejscu i zwraca referencje do niego,
// co umozliwia tzw. lancuchowanie operacji np. a += b += c.
Czas& Czas::operator+=(Czas& inny)
{
this->godzina += inny.godzina;
this->minuta += inny.minuta;
this->sekunda += inny.sekunda;
this->przeliczCzas();
return *this;
}
// ustawCzas jako jedyna publiczna metoda ustawiajaca wywoluje przeliczCzas,
// co gwarantuje, ze czas zawsze bedzie w poprawnym formacie.
void Czas::ustawCzas(int godz, int min, int sek)
{
godzina = godz;
minuta = min;
sekunda = sek;
przeliczCzas();
}
// Operator + tworzy nowy obiekt Czas bedacy suma dwoch czasow,
// nie modyfikuje zadnego z oryginalnych obiektow.
Czas Czas::operator+(Czas& inny)
{
Czas temp;
int g = godzina + inny.godzina;
int m = minuta + inny.minuta;
int s = sekunda + inny.sekunda;
temp.ustawCzas(g, m, s);
return temp;
}
// Operator < porownuje dwa czasy leksykograficznie:
// najpierw godziny, potem minuty, na koncu sekundy.
bool Czas::operator<(Czas& inny)
{
if (godzina < inny.godzina) return true;
if (godzina > inny.godzina) return false;
if (minuta < inny.minuta) return true;
if (minuta > inny.minuta) return false;
if (sekunda < inny.sekunda) return true;
if (sekunda > inny.sekunda) return false;
else return false;
}
// Operator == sprawdza rownosc wszystkich trzech skladowych.
bool Czas::operator==(Czas& inny)
{
return godzina == inny.godzina && minuta == inny.minuta && sekunda == inny.sekunda;
}
// Pozostale operatory relacyjne sa zdefiniowane przez operator== i operator<,
// co eliminuje powtarzanie kodu (wskazowka z instrukcji do projektu).
bool Czas::operator!=(Czas& inny) { return !(*this == inny); }
bool Czas::operator>(Czas& inny) { return inny < *this; }
bool Czas::operator<=(Czas& inny) { return !(*this > inny); }
bool Czas::operator>=(Czas& inny) { return !(*this < inny); }
// przeliczCzas naprawia wartosci wychodzace poza zakres
// (np. 75 sek -> 1 min 15 sek) oraz zeruje wartosci ujemne.
void Czas::przeliczCzas()
{
if (sekunda >= 60) { minuta += sekunda / 60; sekunda = sekunda % 60; }
if (minuta >= 60) { godzina += minuta / 60; minuta = minuta % 60; }
if (sekunda < 0) sekunda = 0;
if (minuta < 0) minuta = 0;
if (godzina < 0) godzina = 0;
}
// Publiczne akcesory odczytujace - zwracaja wartosci prywatnych atrybutow.
int Czas::pobierzgodz() { return godzina; }
int Czas::pobierzmin() { return minuta; }
int Czas::pobierzsek() { return sekunda; }
// Prywatne akcesory ustawiajace - uzywane wewnatrz klasy,
// kazdy po ustawieniu wywoluje przeliczCzas dla bezpieczenstwa.
void Czas::ustawgodz(int godz) { godzina = godz; przeliczCzas(); }
void Czas::ustawmin(int min) { minuta = min; przeliczCzas(); }
void Czas::ustawsek(int sek) { sekunda = sek; przeliczCzas(); }
// Wypisuje czas w formacie godzina:minuta:sekunda.
void Czas::wypiszczas()
{
std::cout << godzina << ":" << minuta << ":" << sekunda << std::endl;
}
// ============================================================
// KLASA HARMONOGRAM
// Kontener przechowujacy dynamicznie rozszerzalna tablice
// obiektow Czas. Spelnia zasade trzech: ma destruktor,
// konstruktor kopiujacy i operator przypisania.
// ============================================================
class Harmonogram
{
private:
Czas* tablica; // wskaznik na dynamicznie alokowana tablice obiektow Czas
int rozmiar; // aktualna liczba elementow w tablicy
public:
// Konstruktor domyslny - tworzy pusty harmonogram.
// Wskaznik ustawiony na nullptr, rozmiar na 0.
Harmonogram()
: tablica(nullptr)
, rozmiar(0)
{
}
// Destruktor - zwalnia pamiec dynamiczna zajeta przez tablice.
// Wymagany przez zasade trzech (klasa zarzadza pamiecia dynamiczna).
~Harmonogram()
{
if (tablica != nullptr)
{
delete[] tablica;
}
}
// Konstruktor kopiujacy - wykonuje glebokie kopiowanie tablicy,
// tzn. alokuje nowa pamiec i kopiuje do niej zawartosc oryginalu.
// Bez tego obie kopie dzielilby ten sam obszar pamieci (plytka kopia).
Harmonogram(const Harmonogram& inny)
{
rozmiar = inny.rozmiar;
if (rozmiar > 0)
{
tablica = new Czas[rozmiar];
for (int i = 0; i < rozmiar; i++)
{
tablica[i] = inny.tablica[i];
}
}
else
{
tablica = nullptr;
}
}
// Operator przypisania - analogicznie do konstruktora kopiujacego
// wykonuje glebokie kopiowanie. Dodatkowo sprawdza czy nie przypisujemy
// obiektu do samego siebie (h1 = h1) i zwalnia stara pamiec przed
// przypisaniem nowej, zeby uniknac wycieku pamieci.
Harmonogram& operator=(const Harmonogram& inny)
{
if (this == &inny)
{
return *this;
}
if (tablica != nullptr)
{
delete[] tablica;
}
rozmiar = inny.rozmiar;
if (rozmiar > 0)
{
tablica = new Czas[rozmiar];
for (int i = 0; i < rozmiar; i++)
{
tablica[i] = inny.tablica[i];
}
}
else
{
tablica = nullptr;
}
return *this;
}
// Operator pre-dekrementacji (--h): usuwa ostatni czas z harmonogramu
// i zwraca referencje do juz zmniejszonego obiektu. Zawiera zabezpieczenie
// przed proba usuniecia elementu z pustego harmonogramu.
Harmonogram& operator--()
{
if (rozmiar == 0)
{
std::cout << "Harmonogram jest juz pusty, nie mozna usunac elementu." << std::endl;
return *this;
}
int nowyRozmiar = rozmiar - 1;
// Jesli po usunieciu harmonogram jest pusty, zwalniamy pamiec
// i ustawiamy wskaznik na nullptr - tak jak w konstruktorze domyslnym.
if (nowyRozmiar == 0)
{
delete[] tablica;
tablica = nullptr;
rozmiar = 0;
return *this;
}
// Alokujemy nowa, mniejsza tablice, kopiujemy wszystkie
// elementy oprocz ostatniego, zwalniamy stara tablice.
Czas* nowaTablica = new Czas[nowyRozmiar];
for (int i = 0; i < nowyRozmiar; i++)
{
nowaTablica[i] = tablica[i];
}
delete[] tablica;
tablica = nowaTablica;
rozmiar = nowyRozmiar;
return *this;
}
// Tworzy nowy harmonogram zawierajacy tylko tyle pierwszych czasow,
// ktorych laczna suma nie przekracza podanego limitu czasowego.
Harmonogram kopiujlimit(Czas limit)
{
Harmonogram nowyHarmonogram;
Czas suma;
for (int i = 0; i < rozmiar; i++)
{
Czas obecnyCzas = tablica[i];
Czas nowaSuma = suma + obecnyCzas;
if (nowaSuma <= limit)
{
nowyHarmonogram.dodajczas(obecnyCzas);
suma += obecnyCzas;
}
else
{
break;
}
}
return nowyHarmonogram;
}
// Zwraca aktualna liczbe elementow w harmonogramie.
int pobierzrozmiar()
{
return rozmiar;
}
// Dodaje nowy czas na koniec harmonogramu. Alokuje nowa tablice
// o rozmiarze wiekszym o 1, kopiuje stare elementy, dodaje nowy
// i zwalnia stara tablice - to reczna implementacja rozszerzalnej tablicy.
void dodajczas(Czas nowy)
{
int nowyRozmiar = rozmiar + 1;
Czas* nowaTablica = new Czas[nowyRozmiar];
for (int i = 0; i < rozmiar; i++)
{
nowaTablica[i] = tablica[i];
}
nowaTablica[rozmiar] = nowy;
if (tablica != nullptr)
{
delete[] tablica;
}
tablica = nowaTablica;
rozmiar = nowyRozmiar;
}
// Zwraca referencje do elementu o podanym indeksie,
// co umozliwia bezposrednia edycje czasu w harmonogramie.
Czas& pobierzCzas(int indeks)
{
return tablica[indeks];
}
// Wypisuje wszystkie czasy z harmonogramu wraz z ich indeksami.
void wypiszWszystkie()
{
for (int i = 0; i < rozmiar; i++)
{
std::cout << i << ". Czas: ";
tablica[i].wypiszczas();
}
}
// Sumuje wszystkie czasy z harmonogramu i zwraca wynik
// jako nowy obiekt Czas.
Czas sumujCzasy()
{
Czas suma;
for (int i = 0; i < rozmiar; i++)
{
suma += tablica[i];
}
return suma;
}
};
// ============================================================
// FUNKCJA MAIN - testy wszystkich funkcjonalnosci
// ============================================================
int main()
{
// --- Testy oryginalne z etapu 4 projektu ---
std::cout << " h1 " << std::endl;
Harmonogram h1;
h1.dodajczas(Czas(0, 5, 0));
h1.dodajczas(Czas(0, 10, 0));
h1.dodajczas(Czas(0, 15, 0));
h1.dodajczas(Czas(0, 20, 0));
h1.dodajczas(Czas(0, 30, 0));
std::cout << "Zawartosc h1:" << std::endl;
h1.wypiszWszystkie();
// Test konstruktora kopiujacego - h2 jest gleboka kopia h1.
Harmonogram h2(h1);
// Test operatora przypisania - h3 jest przypisany z h1.
Harmonogram h3;
h3 = h1;
std::cout << "\n limit" << std::endl;
Czas limit1(0, 25, 0);
std::cout << "limit 00:25:00" << std::endl;
Harmonogram nowyH1 = h1.kopiujlimit(limit1);
nowyH1.wypiszWszystkie();
std::cout << "\nTest 1 zakres 00:50:00" << std::endl;
Czas limit2(0, 50, 0);
Harmonogram nowyH2 = h1.kopiujlimit(limit2);
nowyH2.wypiszWszystkie();
std::cout << "\nTest 2 zakres 0:02:00 " << std::endl;
Czas limit3(0, 2, 0);
Harmonogram nowyH3 = h1.kopiujlimit(limit3);
nowyH3.wypiszWszystkie();
if (nowyH3.pobierzrozmiar() == 0)
{
std::cout << "Harmonogram jest pusty" << std::endl;
}
// --- Test operatora pre-dekrementacji ---
std::cout << "\n=== Test pre-dekrementacji (--h) ===" << std::endl;
Harmonogram hPre;
hPre.dodajczas(Czas(0, 5, 0));
hPre.dodajczas(Czas(0, 10, 0));
hPre.dodajczas(Czas(0, 15, 0));
std::cout << "hPre przed --hPre (rozmiar: " << hPre.pobierzrozmiar() << "):" << std::endl;
hPre.wypiszWszystkie();
// Przypisujemy zwrocona referencje do wynik - to ten sam obiekt co hPre,
// bo operator zwraca *this, czyli referencje do zmniejszonego harmonogramu.
Harmonogram& wynik = --hPre;
std::cout << "hPre po --hPre (rozmiar: " << hPre.pobierzrozmiar() << "):" << std::endl;
hPre.wypiszWszystkie();
std::cout << "Zwrocony obiekt przez --hPre (rozmiar: " << wynik.pobierzrozmiar() << "):" << std::endl;
wynik.wypiszWszystkie();
// Test zabezpieczenia: proba dekrementacji pustego harmonogramu
// powinna wypisac komunikat i nie spowodowac bledu programu.
std::cout << "\n=== Test zabezpieczenia przed dekrementacja pustego harmonogramu ===" << std::endl;
Harmonogram hPusty;
std::cout << "Proba --hPusty:" << std::endl;
--hPusty;
return 0;
}
hpre w harmonogramie czasu
- Rejestracja: dni
- Ostatnio: dni
- Postów: 1
- Rejestracja: dni
- Ostatnio: dni
Powinieneś jasno postawić pytanie, bo nie jest oczywiste o co pytasz co jest probelmem, a program się kompiluje i sanitizer nie znajduje błędów: v
Dopiero jak przeczyta się komentarz:
// Test zabezpieczenia: proba dekrementacji pustego harmonogramu // powinna wypisac komunikat i nie spowodowac bledu programu.
I że logi programu kończą się:
=== Test zabezpieczenia przed dekrementacja pustego harmonogramu ===
Proba --hPusty:
Harmonogram jest juz pusty, nie mozna usunac elementu.
Pytanie robi się jaśniejsze.
Super że wpadłeś, że można pisać testy do programu. To się chwali.
Powinieneś się zainteresować jakąś biblioteką do testów. Google Test jest standardem przemysłowym, a Catch2 jest bardziej przyjazny (słabiej się skaluje).
- Rejestracja: dni
- Ostatnio: dni
Tutaj AI przepisało twoją funkcję main na Google Test. Nie sprawdzałem, czy to dokładnie odpowiada twoim testom.
Niestety, ponieważ obsługę błędów masz dodaną na zasadzie jedynie wyświetlania na std::cout to nie był w stanie dodać asercji wykrywającej twój problem.
Na razie nie mam czasu, by samemu odczytać twój program.
- Rejestracja: dni
- Ostatnio: dni
Ok jednak nie rozumiem w czym problem:
Jest test:
TEST(HarmonogramTest, PreDekrementacjaPustegoHarmonogramuWypisujeBladIRozmiarPozostaje0)
{
Harmonogram h;
testing::internal::CaptureStdout();
--h;
std::string output = testing::internal::GetCapturedStdout();
EXPECT_FALSE(output.empty());
EXPECT_EQ(h.pobierzrozmiar(), 0);
}
wydawało mi się, że o ten problem ci chodzi. Test jest prawidłowy i przechodzi zgodnie z oczekiwaniem.
Jaki jest twój problem? Który z twoich testów nie działa? Możesz dodać analogiczny w gtest:
Nawet zrobiłem ten test bardziej restrykcyjny:
TEST(HarmonogramTest, PreDekrementacjaPustegoHarmonogramuWypisujeBladIRozmiarPozostaje0)
{
Harmonogram h;
testing::internal::CaptureStdout();
--h;
std::string output = testing::internal::GetCapturedStdout();
EXPECT_FALSE(output.empty());
EXPECT_THAT(output, testing::HasSubstr("Harmonogram jest juz pusty"));
EXPECT_EQ(h.pobierzrozmiar(), 0);
}