• 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
836 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 974 wizyt
0 głosów
1 odpowiedź 188 wizyt
0 głosów
2 odpowiedzi 1,015 wizyt
pytanie zadane 8 grudnia 2018 w C i C++ przez dawid2002 Mądrala (5,190 p.)

92,536 zapytań

141,377 odpowiedzi

319,456 komentarzy

61,922 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

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

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!

...