Nie działająca klasa

0

Dlaczego to nie chce działać, przekazując adresy, do wskażników działa, ale jeśli przekazuje po prostu klase to nie działa
no matching function to call Towar:Towar() ? what?

#include <iostream>
using namespace std;
 
class Towar {
protected:
    string nazwa;
 
public:
    virtual void sprzedaj();
 
    Towar(string nazwa)
        : nazwa(nazwa)
    {
    }
};
 
void Towar::sprzedaj()
{
    cout << "Sprzedarz " << nazwa << endl;
}
 
class Towar_z_Gwarancja : public Towar {
protected:
    string podbicie_gwarancji;
 
public:
    void sprzedaj();
    Towar_z_Gwarancja(string nazwa, string podbicie_gwarancji)
        : Towar(nazwa)
        , podbicie_gwarancji(podbicie_gwarancji){};
};
 
void Towar_z_Gwarancja::sprzedaj()
{
    Towar::sprzedaj();
    cout << ".Podbicie gwarancji\n";
}
 
class Koszyk {
public:
    int i;
    Towar koszyk[10];
 
    Koszyk(int i = 0)
        : i(i){};
 
    void Dodaj_Towar_do_Koszyka(Towar towar)
    {
        if (i <= 9) {
            koszyk[i] = towar;
            ++i;
        }
    }
};
 
int main(int argc, char** argv)
{
 
    Towar towarek1("jablko");
    Towar_z_Gwarancja towarek2("sok", "3.11.1997");
    Koszyk koszyk1;
    koszyk1.Dodaj_Towar_do_Koszyka(towarek1);
    koszyk1.Dodaj_Towar_do_Koszyka(towarek2);
 
    return 0;
}
0

Ale co nie działa? Wypadałoby opisać.

Błąd zgłaszany przez kompilator dość jasno mówi, że klasa Towar nie ma konstruktora domyślnego, który próbujesz wołać.

0

no to teraz mam bardzo ważne pytanie:

  1. co się dzieje jak do obiektu klasy Towar, np.
    przekazuje w kodzie poniżej do funkcji void Dodaj_Towar_do_Koszyka(Towar towar)
    obiekt towarek2 (Towar_z_Gwarancja towarek2("sok", "3.11.1997");) i teraz co się dzieje, bo nie wiem,
    czy to co jest w klasie pochodnej, a nie ma w klasie bazowej to jest ucianane?
    bo pomimo metody wirtualnej virtual void sprzedaj(); po wywołaniu funkcji sprzedaj() zostaje wywołana funkcja sprzedaj z klasy bazowej a nie pochodnej (w przypadku 2 wywołania)
#include <iostream>
using namespace std;

class Towar {
public:
    string nazwa;

public:
    virtual void sprzedaj();
    Towar(){};
    Towar(string nazwa)
        : nazwa(nazwa)
    {
    }
};

void Towar::sprzedaj()
{
    cout << "Sprzedarz " << nazwa << endl;
}

class Towar_z_Gwarancja : public Towar {
protected:
    string podbicie_gwarancji;

public:
    void sprzedaj();
    Towar_z_Gwarancja(string nazwa, string podbicie_gwarancji)
        : Towar(nazwa)
        , podbicie_gwarancji(podbicie_gwarancji){};
};

void Towar_z_Gwarancja::sprzedaj()
{
    Towar::sprzedaj();
    cout << ".Podbicie gwarancji\n";
}

class Koszyk {
public:
    int i;
    Towar koszyk[10];

    Koszyk(int i = 0)
        : i(i){};

    void Dodaj_Towar_do_Koszyka(Towar towar)
    {
        if (i <= 9) {
            koszyk[i] = towar;
            cout << koszyk[i].nazwa << endl;
            koszyk[i].sprzedaj();
            ++i;
        }
    }
};

int main(int argc, char** argv)
{

    Towar towarek1("jablko");
    Towar_z_Gwarancja towarek2("sok", "3.11.1997");
    Koszyk koszyk1;
    koszyk1.Dodaj_Towar_do_Koszyka(towarek1);
    koszyk1.Dodaj_Towar_do_Koszyka(towarek2);

    return 0;
}
1

Tak, to jest po angielsku slicing, inicjalizujesz nową instancję klasy Towar za pomocą przekazanego elementu. Ponieważ Towar_z_Gwarancja może być traktowany jako Towar, dokładnie tak się dzieje, i kopiowane są tylko jego bazowe elementy.

więcej tu: https://stackoverflow.com/questions/274626/what-is-object-slicing

0

a jak przekazuje do Towar* wsk adres oiektu klasy pochodnej to po prostu ten wskaznik wsk przechowje tylko pamięć w której się znajduje obiekt klasy pochodnej?
tak samo jak w wskażniku do struktury

1

Przy takim przypisaniu adresu obiektu klasy pochodnej do wskaźnika klasy bazowej, zachodzić mogą 2 przypadki:

  • Jeśli metoda nie posiadała virtual, zadziała to jak by zachodził slicing (tak jak wcześniej). Pamięć nie jest uszkadzana i obiekty dostępne są w całości ale nie ma wbudowanej w język metody rozpoznania na rzecz którego obiektu metodę wywołujemy przy takiej składni.
  • Jeśli metoda posiadała virtual, ma nastąpić identyfikacja wskaźnika do prawdziwego typu obiektu. Kompilatory realizują to najczęściej poprzez tworzenie tablicy Vtable w której zapisują jaką metodę wołać dla jakiego typu obiektu pochodnego. Standard języka nie definiuje jak to ma być zrobione tylko jak ma działać :-)

Nie ma nic za darmo :-/ Drugi przypadek powoduje że klasa "puchnie"...
Tu masz szybki przykład:

#include <iostream>

// Sliced
class XSlice {
public:
    void foo() {
        std::cout << "XSlice::foo()\n";
    }
};

class YSlice: public XSlice {
public:
    void foo() {
        std::cout << "YSlice::foo()\n";
    }
};

// Virtual
class XVirtual {
public:
    virtual void foo() {
        std::cout << "XVirtual::foo()\n";
    }
};

class YVirtual: public XVirtual {
public:
    void foo() override {
        std::cout << "YVirtual::foo()\n";
    }
};

int main() {
    XSlice xslice;
    YSlice yslice;
    XSlice * ptr_xslice = &yslice;

    XVirtual xvirtual;
    YVirtual yvirtual;
    XVirtual * ptr_xvirtual = &yvirtual;

    ptr_xslice->foo();

    std::cout << "sizeof(xslice) = " << sizeof(xslice)
        << "\nsizeof(yslice) = " << sizeof(yslice) << '\n';

    std::cout << '\n';

    ptr_xvirtual->foo();

    std::cout << "sizeof(xvirtual) = " << sizeof(xvirtual) 
        << "\nsizeof(yvirtual) = " << sizeof(yvirtual) << '\n';
}
1
Mokrowski napisał(a):

Przy takim przypisaniu adresu obiektu klasy pochodnej do wskaźnika klasy bazowej, zachodzić mogą 2 przypadki:

  • Jeśli metoda nie posiadała virtual, zachodzi slicing tak jak wcześniej.

Do pierwszego punktu ważna uwaga. Tu NIE zachodzi slicing, ale po prostu metoda niewirualna traktuje obiekt jakby był klasy bazowej. W pamięci nadal on jest nieucięty, ale działa jakby był. W związku z tym, będzie tak, że dla metody wirtualnej będzie się zachowywał jak obiekt klasy pochodnej, a dla niewirtualnej -- bazowej.

0

dziękuje

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