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

Przeciążanie metod wirtualnych, a kontener tablicy (std::vector)

Object Storage Arubacloud
+1 głos
889 wizyt
pytanie zadane 19 sierpnia 2016 w C i C++ przez plkpiotr Stary wyjadacz (12,420 p.)
edycja 22 sierpnia 2016 przez plkpiotr

Bardzo proszę o wyjaśnienie błędu, co robię niepoprawnie. Piszę program w C++, który wykorzystuje zagadnienia poliformizmu, funkcji wirtualnych oraz kontenerów na temat kadry pracowniczej. Kompilował się on bez zarzutów dopóki nie zacząłem pisać funkcji wirtualnych...

Komunikat od kompilatora:

||=== Build: Debug in ehh (compiler: GNU GCC Compiler) ===|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\bits\stl_vector.h||In instantiation of 'class std::vector<Pracownik>':|
D:\00 Kody\ehh\main.cpp|13|required from here|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\bits\stl_vector.h|713|error: invalid abstract parameter type 'Pracownik'|
D:\00 Kody\ehh\pracownik.h|17|note:   because the following virtual functions are pure within 'Pracownik':|
D:\00 Kody\ehh\pracownik.h|30|note:     virtual void Pracownik::obliczZarobki()|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\bits\vector.tcc||In instantiation of 'void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, const _Tp&) [with _Tp = Pracownik; _Alloc = std::allocator<Pracownik>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<Pracownik*, std::vector<Pracownik> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = Pracownik*]':|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\bits\stl_vector.h|925|required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Pracownik; _Alloc = std::allocator<Pracownik>; std::vector<_Tp, _Alloc>::value_type = Pracownik]'|
D:\00 Kody\ehh\main.cpp|14|required from here|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\bits\vector.tcc|337|error: cannot allocate an object of abstract type 'Pracownik'|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\bits\vector.tcc|337|error: cannot declare variable '__x_copy' to be of abstract type 'Pracownik'|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\ext\new_allocator.h||In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(__gnu_cxx::new_allocator<_Tp>::pointer, const _Tp&) [with _Tp = Pracownik; __gnu_cxx::new_allocator<_Tp>::pointer = Pracownik*]':|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\ext\alloc_traits.h|189|required from 'static void __gnu_cxx::__alloc_traits<_Alloc>::construct(_Alloc&, __gnu_cxx::__alloc_traits<_Alloc>::pointer, const _Tp&) [with _Tp = Pracownik; _Alloc = std::allocator<Pracownik>; __gnu_cxx::__alloc_traits<_Alloc>::pointer = Pracownik*]'|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\bits\stl_vector.h|918|required from 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Pracownik; _Alloc = std::allocator<Pracownik>; std::vector<_Tp, _Alloc>::value_type = Pracownik]'|
D:\00 Kody\ehh\main.cpp|14|required from here|
c:\mingw\lib\gcc\mingw32\4.9.3\include\c++\ext\new_allocator.h|130|error: invalid new-expression of abstract class type 'Pracownik'|
||=== Build failed: 4 error(s), 9 warning(s) (0 minute(s), 0 second(s)) ===|

Natomiast kod udostępniłem poniżej:

//=======================================
// Nazwa  : pracownik.h
//=======================================

#ifndef PRACOWNIK_H
#define PRACOWNIK_H
#include <iostream>
#include <cstdio>
#include <string>
#define PROCENT 1.5

using namespace std;

class Pracownik
{
private:
    bool zatrudnienie;
    string imie;
    string nazwisko;
    string pesel;
    string nip;
public:
    Pracownik();
    Pracownik(string im, string nzwsk, string psl, string np);
    //void zmianaZatrudnienia(Pracownik prcwnk);
    //virtual void wyswietlDane() = 0;
    virtual void obliczZarobki() = 0;
    virtual ~Pracownik() {};
    // jest to jednoczesnie implementacja
    // zastanowić się gdyby nie było destruktora
};

class Staly: public Pracownik
{
private:
    double wynagrodzenie;
public:
    Staly();
    Staly(string im, string nzwsk, string psl, string np, double wngrdzn);
    void obliczZarobki() {} //musi być kurcze
    //void wyswietlDane(); // const
    ~Staly() {};
};

class Zleceniobiorca: public Pracownik
{
private:
    double stawka;
    int godziny;
    double wynagrodzenie;
public:
    Zleceniobiorca();
    Zleceniobiorca(string im, string nzwsk, string psl, string np, double stwk, int gdzn);
    //void wyswietlDane(); // const
    void obliczZarobki();
    ~Zleceniobiorca() {}
};

class Handlujacy: public Pracownik
{
private:
    double wartosc;
    int transakcje;
    double wynagrodzenie;
public:
    Handlujacy();
    Handlujacy(string im, string nzwsk, string psl, string np, double wrtsc, int trnskcj);
    //void wyswietlDane(); // const
    void obliczZarobki();
    ~Handlujacy() {}
};

void czyszczenie();
#endif
//=======================================
// Nazwa  : pracownik.cpp
//=======================================

#include "pracownik.h"

Pracownik::Pracownik()
{
    cout << "Wprowadzanie danych nowego pracownika..." << endl;
    cout << "Imie: ";
    cin >> imie;
    cout << "Nazwisko: ";
    cin >> nazwisko;
    cout << "Pesel: ";
    cin >> pesel;
    cout << "Numer identyfikacji podatkowej: ";
    cin >> nip;
}

Pracownik::Pracownik(string im, string nzwsk, string psl, string np)
{
    zatrudnienie = true;
    imie = im;
    nazwisko = nzwsk;
    pesel = psl;
    nip = np;
}

Staly::Staly(): Pracownik()
{
    cout << "Miesieczne wynagrodzenie: ";
    cin >> wynagrodzenie;
}

Staly::Staly(string im, string nzwsk, string psl, string np, double wngrdzn): Pracownik(im, nzwsk, psl, np)
{
    wynagrodzenie = wngrdzn;
}

Zleceniobiorca::Zleceniobiorca(): Pracownik()
{
    cout << "Godzinna stawka: ";
    cin >> stawka;
    cout << "Przepracowane godziny: ";
    cin >> godziny;
}

Zleceniobiorca::Zleceniobiorca(string im, string nzwsk, string psl, string np, double stwk, int gdzn): Pracownik(im, nzwsk, psl, np)
{
    stawka = stwk;
    godziny = gdzn;
}

Handlujacy::Handlujacy(): Pracownik()
{
    cout << "Wartosc pojedynczej transakcji: ";
    cin >> wartosc;
    cout << "Ilosc transakcji: ";
    cin >> transakcje;
}

Handlujacy::Handlujacy(string im, string nzwsk, string psl, string np, double wrtsc, int trnskcj): Pracownik(im, nzwsk, psl, np)
{
    wartosc = wrtsc;
    transakcje = trnskcj;
}

void Zleceniobiorca::obliczZarobki()
{

}

void Handlujacy::obliczZarobki()
{

}

void czyszczenie()
{
    printf("\033[2J"); // Czyści ekran
    printf("\033[0;0f"); // Ustawia kursor w lewym, górnym rogu
}
//=======================================
// Nazwa  : main.cpp
//=======================================

#include <vector>
#include "pracownik.h"

int main()
{
    vector <Pracownik> baza;
    baza.push_back(Staly("Piotr","Wierchowieński","63032300373","4457301037",3300));
    baza.push_back(Staly("Mikołaj","Stawrogin","89102905493","7260631988",4100));
    baza.push_back(Zleceniobiorca("Iwan","Szatow","77082213114","6825506522",2300,40));
    baza.push_back(Zleceniobiorca("Aleksy","Kiriłłow","85052403018","5913117469",2700,25));
    baza.push_back(Handlujacy("Sergiusz","Liputin","67052801713","4621950579",560,14));
    baza.push_back(Handlujacy("Ignacy","Lebiadkin","79091902931","8442924521",770,10));
    int wybor;
    do
    {
        cout << "Edycja kadry pracowniczej:" << endl;
        cout << "[1] --> Dodaj stalego pracownika na koncu danych" << endl;
        cout << "[2] --> Dodaj zleceniobiorce na koncu danych" << endl;
        cout << "[3] --> Dodaj handulajcego na koncu danych" << endl;
        cout << "[4] --> Zmien stan zatrudnienia pracownika" << endl; // zastanowi  si
        cout << "[5] --> Usun pracownika z kadry" << endl;
        cout << "[6] --> Usun cala kadre" << endl;
        cout << "[0] --> Wyjscie" << endl;
        cout << "Twoj wybor: " << endl;
        do
        {
            cin.clear();
            cin.sync();
            cin >> wybor;
        }
        while(!cin.good());
        switch(wybor)
        {
        case 1 :
            baza.push_back(Staly());
            break;
        case 2 :
            baza.push_back(Zleceniobiorca());
            break;
        case 3 :
            baza.push_back(Handlujacy());
            break;
        case 4 :
            break;
        case 5 :
            break;
        case 6 :
            break;
        }
    }
    while(wybor!=0);
    return 0;
}

 

3 odpowiedzi

+2 głosów
odpowiedź 19 sierpnia 2016 przez obl Maniak (51,280 p.)
wybrane 19 sierpnia 2016 przez plkpiotr
 
Najlepsza

class std::vector<Pracownik> - próbujesz stworzyć kontener zawierający obiekty klasy abstrakcyjnej? To nie przejdzie, bo obiektu takiej klasy nie możesz utworzyć. Możesz jedynie przechowywać wskaźniki: std::vector<Pracownik*> w takim kontenerze, przy czym pamiętać musisz, że wskaźnika klasy abstrakcyjnej nie tworzy się tak:

Pracownik* p = new Pracownik( // coś tam

bo to też nie przejdzie, ale robi się to tak:

Pracownik* p = new Stały( //coś tam

Nie wnikam w resztę błędów, bo prawdopodobnie wynikają one z tego co napisałem.

komentarz 19 sierpnia 2016 przez plkpiotr Stary wyjadacz (12,420 p.)
Dziękuję bardzo ; )
Zrozumiane :D
1
komentarz 19 sierpnia 2016 przez obl Maniak (51,280 p.)
Z tego co widzę, to sam sobie poradziłeś (i bardzo dobrze) a ja chwilę po to tobie odpisałem :)
1
komentarz 19 sierpnia 2016 przez plkpiotr Stary wyjadacz (12,420 p.)
Tak :) Zauważyłem w porę swój błąd, chyba trzeba będzie używać metody gumowej kaczuszki, a forum odwiedzać dopiero w ostateczności ;) Tak to jest gdy długo się siedzi nad kodem bez przerwy... Dzięki raz jeszcze :)
+3 głosów
odpowiedź 19 sierpnia 2016 przez plkpiotr Stary wyjadacz (12,420 p.)

Wszystko jasne - zapomniałem w jaki sposób implementuje się obiekty, gdy mamy do czynienia z funkcjami wirtualnymi...

Zabrakło podejścia jak z wskaźnikami z * oraz new

vector <Pracownik*> baza;
baza.push_back(new Staly("Piotr","Wierchowieński","63032300373","4457301037",3300));
    

 

1
komentarz 20 sierpnia 2016 przez criss Mędrzec (172,590 p.)
Tylko pamiętaj że to jest dynamiczna alokacja i musisz zadbać o zwolnienie pamięci obiektu przy wyrzucaniu wskaźnika z kontenera. Dla bezpieczenstwa użyj std::shared_ptr
komentarz 22 sierpnia 2016 przez plkpiotr Stary wyjadacz (12,420 p.)
edycja 22 sierpnia 2016 przez plkpiotr
Dziękuję za uwagę ;)
Jednak może tak sztubacko zapytam - czy używanie metody erase() nie załatwi zwalniania pamięci?
1
komentarz 22 sierpnia 2016 przez criss Mędrzec (172,590 p.)
edycja 22 sierpnia 2016 przez criss
Nie, dlaczego miałaby to robić? Wyrzuca z kontenera wskaźnik (a wskaźnik tylko wskazuje). Inaczej by sprawa wyglądała gdybyś trzymał w kontenerze np. std::unique_ptr - wtedy obiekt jest niszczony, ale nie odpowiada za to erase, tylko destruktor unique_ptr.
komentarz 22 sierpnia 2016 przez plkpiotr Stary wyjadacz (12,420 p.)
Dziękuję bardzo za klarowne wyjaśnienie :)
–1 głos
odpowiedź 20 sierpnia 2016 przez Damian11131 Stary wyjadacz (13,490 p.)
"Przeładowywanie", a nie "przeciążanie"!

Podobne pytania

+3 głosów
3 odpowiedzi 1,039 wizyt
0 głosów
1 odpowiedź 199 wizyt
0 głosów
2 odpowiedzi 1,050 wizyt
pytanie zadane 8 grudnia 2018 w C i C++ przez dawid2002 Mądrala (5,190 p.)

92,702 zapytań

141,615 odpowiedzi

320,180 komentarzy

62,060 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.

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...