• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wykrywanie tworzenia obiektu w obiekcie c++

VPS Starter Arubacloud
0 głosów
591 wizyt
pytanie zadane 30 listopada 2017 w C i C++ przez chacken Użytkownik (820 p.)

Po krótce szybko wytłumaczę o co biega. Mam zadanie które polega na stworzeniu konstruktorów do klasy w odpowiedni sposób, tak żeby wyświetlały przy inicjalizacji odpowiednie rzeczy. 
Mam klasę Pojazd mającą numer rejestracyjny i wskaźnik na tą samą klasę i w niej metodę "dodaj_przyczepe"

class Pojazd{
    string tablica_rejestracyjna;
    Pojazd *przyczepa = NULL;
public:
    void dodaj_przyczepe(Pojazd *przycz){
            przyczepa = przycz;
        }

Teraz mam stworzyć konstruktory w odpowiedni sposób tak żeby wyświetlały przy tworzeniu obiektu czy "pojazd" jest tworzony jednocześnie z przyczepą:

Pojazd toyota("SGL 1233") // Wypisuje: Konstruktor z parametrem, rej. "SGL 1233", przyczepa: brak
Pojazd * maluch = new Pojazd(); // Wypisuje: Konstruktor domyślny, rej. "Ekstra", przyczepa brak
//I tutaj ten problematyczny przypadek:
toyota.dodaj_przyczepę(new Pojazd("SAW 1122")); // Wypisuje: Konstruktor domyślny, rej. "SAW 1122"

W tym ostatnim przypadku nie ma dopisane "brak przyczepy"... gdy tworzy obiekt zauważa w jakiś sposób że to jest "przyczepa" a raczej że jest to tworzone w ramach innego obiektu i nie wiem jak to zauważyć.... narazie wymyśliłem jak "potem" to może sprawdzić za pomocą NULL ale nie wiem jak sprawdzić to w momencie tworzenia obiektu, to moje konstruktory... a raczej wkleję po prostu całą klasę i main:

 

class Pojazd{
    string tablica_rejestracyjna;
    Pojazd *przyczepa = NULL;
    static int suma;


public:
    Pojazd(){
        tablica_rejestracyjna = "Ekstra";
        string czy_jest = "przyczepa: brak";
        if(przyczepa != NULL)
            czy_jest = "";

        cout << "Konstruktor domyslny: " << tablica_rejestracyjna << "  " << czy_jest << endl;
    }
    explicit Pojazd(string dowolna):tablica_rejestracyjna(dowolna){
        string czy_jest = "przyczepa: brak";
        if(przyczepa != NULL)
            czy_jest = "";

        cout << "Konstruktor z parametrem: " << tablica_rejestracyjna << "  " << czy_jest << endl;
    };
    ~Pojazd(){
        string czy_jest = "przyczepa: brak";
        if(przyczepa != NULL)
            czy_jest = "";

        cout << "Destruktor: rejestracja " << tablica_rejestracyjna << "  " << czy_jest << endl;
    };
    void dodaj_przyczepe(Pojazd *przycz){
        przyczepa = przycz;
    }
};

int main() {
    Pojazd toyota("SGL 1234");
    Pojazd *maluch = new Pojazd();
    delete maluch;
    toyota.dodaj_przyczepe(new Pojazd("SGL 334"));
    return 0;
)

Ogólnie to potem po stworzeniu obiektu działa i widzi że jest przyczepa co widać przy użyciu destruktora.... ale co zrobić żeby w momencie tworzenia klasa sama z siebie zauważała że "oho! obiekt tworzony jest na potrzeby innej klasy.... więc to jest przyczepa... wyświetlę inny tekst bez "brak przyczepy"
Próbowałem coś zrobić z konstruktorem kopiującym bo w zasadzie 
 

toyota.dodaj_przyczepe(new Pojazd("SGL 334"));

To tak trochę skorzystanie z kopiującego konstruktora... tylko przypisanie do starego obiektu nowego... ale nie mam pojęcia jak to dalej wykorzystać.
Byłbym wdzięczny za pomoc

2 odpowiedzi

0 głosów
odpowiedź 1 grudnia 2017 przez obl Maniak (51,280 p.)

Najpierw tworzysz sobie typ enumerowany:

enum wehicles{ car, trailer };

i teraz konstruktory:

	Pojazd(enum wehicles type = wehicles::car):przyczepa(NULL){
        tablica_rejestracyjna = "Ekstra";
		string czy_jest;
		switch(type){
			case wehicles::car:
				czy_jest = "przyczepa: brak";
				break;
			case wehicles::trailer:
				czy_jest = "to jest naczepa!";
				break;
		}
        cout << "Konstruktor domyslny: " << tablica_rejestracyjna << "  " << czy_jest << endl;
    }
    explicit Pojazd(string dowolna, enum wehicles type = wehicles::car):tablica_rejestracyjna(dowolna), przyczepa(NULL){
		string czy_jest;
		switch(type){
			case wehicles::car:
				czy_jest = "przyczepa: brak";
				break;
			case wehicles::trailer:
				czy_jest = "to jest naczepa!";
				break;
		}
        cout << "Konstruktor z parametrem: " << tablica_rejestracyjna << "  " << czy_jest << endl;
    };

tera jak dodajesz przyczepę to robisz to tak:

	toyota.dodaj_przyczepe(new Pojazd("SGL 334", wehicles::trailer));

 

komentarz 1 grudnia 2017 przez chacken Użytkownik (820 p.)

No właśnie chodzi o to żeby nie było nic dodatkowo przekazywane jako parametr tj.
 

toyota.dodaj_przyczepe(new Pojazd("SGL 334")

i już wykrywa że to przyczepa... nie mam pojęcia ;/

komentarz 1 grudnia 2017 przez obl Maniak (51,280 p.)
Twoja klasa Pojazd opisuje tak na prawdę dwa rodzaje obiektów w jednym, czyli przyczepę i samochód nie widząc żadnej różnicy pomiędzy jednym a drugim. Takie rozróżnienie można wprowadzić np za pomocą konstruktora umożliwiającego rozróżnienie czym tak naprawdę jest ten twój pojazd.
komentarz 1 grudnia 2017 przez chacken Użytkownik (820 p.)
Ehhh.... no właśnie wiem że to jest troche takie "w koło Macieju"... ale muszą nam utrudnić życie na laboratoriach....wszystko podchwytliwe i bezsensu, zamiast po polsku opisać co i jak to szyfrem piszą i połowa ludzie oblewa.... nie mówiąc już o podchwytliwym egzaminie.... na którym mój znajomy który zawodowo pisze w Pythinie i Django oblał.... ehh...
komentarz 2 grudnia 2017 przez obl Maniak (51,280 p.)

Można to rozwiązać również wykorzystując polimorfizm, gdzie klasa bazowa będzie interfejsem (klasą abstrakcyjną) Pojazd po niej będzie dziedziczyła klasa Samochod i Przyczepa ale nie wiem, czy to rozwiązanie będzie dla ciebie zrozumiałe. I tak w pojeździe będziesz miał wskaźnik na Pojazd a za nim może stać obiekt klasy Przyczepa lub Samochod bo w końcu samochód może ciągnąć inny samochód.

0 głosów
odpowiedź 1 grudnia 2017 przez mokrowski Mędrzec (156,220 p.)

Ogólnie, to zachowaj reguły hermetyzacji. Jeśli zdecydowałeś się na konstruktor:

  • Domyślny bez parametrów
  • Z jednym parametrem w postaci std::string() z rejestracją

To logicznym będzie przekazywanie do dodaj_przyczepe() także std::string z rejestracją. Niech to klasa Pojazd zarządza czasem życia obiektu przyczepy. Jeśli z jakiegoś powodu masz "udostępniać przyczepę", to zrób to z klasy Pojazd. Z tym ostatnim bym jednak uważał bo dane o przyczepie udostępniasz na zewnątrz i nie wiadomo co i kto z tą przyczepą zrobi.

Przy proponowanym rozwiązaniu, w destruktorze klasy Pojazd, możesz wywołać delete na wskaźniku na przyczepę bez sprawdzania warunku "czy to przypadkiem nie NULL". Dla NULL, destruktor (czyli delete) nie wykona żadnej pracy.

Ja bym to zrobił tak.... z drobnymi poprawkami Twojej pracy:

#include <string>
#include <iostream>

class Pojazd{
    std::string tablica_rejestracyjna;
    std::string czy_jest;
    Pojazd *przyczepa;
    static int suma;
public:
    Pojazd()
        : tablica_rejestracyjna{"Extra"}, czy_jest{"przyczepa: brak"},
            przyczepa{nullptr} {
        std::cout << "Konstruktor domyslny: " << tablica_rejestracyjna
            << "  " << czy_jest << '\n';
    }
    explicit Pojazd(const std::string& rejestracja)
        : tablica_rejestracyjna{rejestracja}, czy_jest{"przyczepa: brak"},
            przyczepa{nullptr} {
        std::cout << "Konstruktor z parametrem: " << tablica_rejestracyjna
            << "  " << czy_jest << '\n';
    };
    /* Konstruktor z przyczepą */
    Pojazd(const std::string& rejestracja, const std::string& rejestracja_przyczepy)
        : tablica_rejestracyjna{rejestracja}, czy_jest{"przyczepa: jest"},
            przyczepa{new Pojazd(rejestracja_przyczepy)} {
    }
    ~Pojazd() {
        std::cout << "Destruktor: rejestracja " << tablica_rejestracyjna << "  "
            << czy_jest << '\n';
        if(przyczepa) {
            std::cout << "Przyczepa: " << przyczepa->tablica_rejestracyjna << '\n';
        }
        delete przyczepa;
    };
    void dodaj_przyczepe(const std::string& rejestracja) {
        /* Zakładam że jeśli istniała przyczepa, należy ją zniszczyć */
        if(przyczepa) {
            delete przyczepa;
        }
        przyczepa = new Pojazd(rejestracja);
        czy_jest = "przyczepa: jest";
    }
};
 
int main() {
    Pojazd toyota("SGL 1234");
    toyota.dodaj_przyczepe("SGL 334");
    Pojazd karawan("VV 666");
    Pojazd laweta("XYZ 3314", "QQ 313");
}

 

komentarz 1 grudnia 2017 przez chacken Użytkownik (820 p.)

Świetnie opisane, dzięki, na pewno coś z tego wezmę... szczególnie ten konstruktor z jednoczesnym tworzeniem przyczepy... ale mam jeszcze jedno pytanie... bo zaszedłem dalej i mam zrobić kolejną klase SalonSamochodowy... która ma w sobie dynamiczną tablicę obiektów Pojazd (tych z pytania) i rozwiązałem taki sam przypadek dla int i działa ale jak pod int podstawiam "Pojazd" to segmentation error, poniżej kod dobry na którym testowałem działanie:

class Zbior{
    int *dane;
    int rozmiar = 0;
public:
    Zbior(){
        dane = new int[rozmiar];
    }
    void dodaj(int a){
        dane[rozmiar] = a;
        rozmiar++;
    };

int main(){
Zbior x;
x.dodaj(1);
x.dodaj(2);
x.dodaj(6);
/// wszystko działa pięknie
}

i to działa pięknie... a teraz przypadek z Pojazdem wygląda na dokładnie taki sam:
 

class SalonSamochodowy{
    Pojazd *dane;
    int liczba_ofert = 0;
public:
    SalonSamochodowy(){
        dane = new Pojazd[liczba_ofert];
    }
    void dodajSamochod(Pojazd &a){
        dane[liczba_ofert] = a;
        liczba_ofert++;
    }

int main() {
Pojazd toyota("toyota123");
Pojazd mercedes("merc456");
Pojazd suzuki("suz789");

SalonSamochodowy ss;
ss.dodajSamochod(toyota) // pierwszy dodaje
ss.dodajSamochod(mercedes) // na drugim leci crach chyba ze ustawię na start większą liczbę ofert

No i tak jak opisałem w przypadku.... pierwszy samochod mi doda ale już kolejnego nie... chyba że ustawię na start większą "liczbę_ofert"... niewiem czemu ale w pierwszym przypadku wszystko pięknie działa dynamicznie a w drugim jest problem... mimo że teoretycznie powinno działać tak samo...
 

komentarz 1 grudnia 2017 przez mokrowski Mędrzec (156,220 p.)
Z uporem maniaka popełniasz ten sam błąd. Zwróć uwagę w którym miejscu inicjuję zmienne w klasie. Ano w konstruktorze.

W linii 6 pierwszego przykładu deklarujesz tablicę o wielkości... 0 elementów! Później w 10 linii zwiększasz licznik mając nadzieję że tablica nagle się rozszerzy. To tak nie działa. Jeśli już upierasz się na pracę na tablicach (co IMHO jest niepotrzebną komplikacją), to deklaruj ją z jakąś wielkością. Pamiętaj także o jej usunięciu przez delete []. Inaczej doprowadzisz do wycieku pamięci.

Jeśli jednak nie chcesz komplikować kodu (co radzę), zmień tablicę na std::vector. Jego metody umożliwiają dynamiczne zwiększenie rozmiaru.
komentarz 1 grudnia 2017 przez chacken Użytkownik (820 p.)
Akurat dodałem nowe zagadnienie :P
Zaraz to obczaję.
komentarz 1 grudnia 2017 przez chacken Użytkownik (820 p.)
Pytanie trochę uprościłem i już trochę zmieniłem składnię.... ale i tak nie działa :(

Właśnie problem taki że ja mam z tego laboratorium i osobiście zrobił bym to 1000-kroć inaczej... osobiście w pythonie piszę, nawet ostatnio zawodowo się zaczęło... ale ten c++ na studiach to mordęga :(
Spójrz proszę na poniższe zagadnienie... tam dodałem też kawałek treści zadania i uprościłem swój problem, wraz z przykładem. Założenia są niestety takie że muszę to (chyba) zrobić właśnie w taki pokręcony sposób... i nie mogę korzystać z udogodnień.

https://forum.pasja-informatyki.pl/307985/dynamiczne-tworzenie-innego-obiektu-w-obiekcie-c

.... a jeszcze śmieszniejsze jest to że bywało ale już nie wiem jaki to był kod że jak odpalałem "run" to się aplikacja crashowała... a jak debugowałem i leciałem krok po kroku to przechodziło....

Podobne pytania

0 głosów
1 odpowiedź 1,252 wizyt

92,843 zapytań

141,782 odpowiedzi

320,858 komentarzy

62,174 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...