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

Problem z klasą abstrakcyjną.

Aruba Cloud VPS - 50% taniej przez 3 miesiące!
0 głosów
276 wizyt
pytanie zadane 27 marca 2017 w C i C++ przez Prg Użytkownik (580 p.)

Dlaczego to nie działa? Tworzę obiekt typu MathStudent, a nie Student, więc kompilator nie powinien mieć "pretensji" z powodu utworzenia obiektu typu klasy abstrakcyjnej.

#include <iostream>
#include <list>
using namespace std;
class Student
{
protected:
	string name;
	string surname;
public:
	virtual void display() const = 0;
};

class MathStudent : public Student
{
private:
	int note;
public:
	void display() const;	
};

int main()
{
	list<Student> students;
	MathStudent * pointer = new MathStudent;
	students.push_back(*pointer);
	
    delete pointer;
    return 0;       
}

 

1 odpowiedź

0 głosów
odpowiedź 27 marca 2017 przez criss Mędrzec (172,590 p.)
 
Najlepsza

I nie czepia się o tworzenie obiektu, tylko o linie z push_back.

Polimorfizm jest mechanizmem wskaźników, nie obiektów. Kontener może przetrzymywać wskaźniki na obiekty klas mających wspólnego rodzica (który posiada chociaż jedną metode wirt. btw), ale nie bezpośrednio ich obiekty.

Działało by tak:

    list<Student *> students;
    MathStudent * pointer = new MathStudent;
    students.push_back(pointer);

A, żeby było ładnie i bezpiecznie - powinno wyglądać tak:

    list<std::unique_ptr<Student>> students;
    students.push_back(std::make_unique<Student>(new MathStudent));

Swoją drogą - klasa Student powinna mieć wirtualny destruktor

komentarz 28 marca 2017 przez mokrowski Mędrzec (156,260 p.)

Powinno być:

std::make_unique<Student>()

.. ponieważ make_unique, przyjmuje argumenty konstruktora klasy którą tworzy. 

komentarz 28 marca 2017 przez criss Mędrzec (172,590 p.)

ponieważ make_unique, przyjmuje argumenty konstruktora klasy którą tworzy. 

Fakt. W takim razie powinno być 
 

students.push_back(std::unique_ptr<Student>(new MathStudent));

(std::make_unique<Student>() będzie próbował tworzyć obiekt std::unique_ptr<Student> który z kolei spróbuje stworzyć obiekt Student, co jest niemożliwe)

komentarz 28 marca 2017 przez mokrowski Mędrzec (156,260 p.)
edycja 28 marca 2017 przez mokrowski

Nie. Powinno być:

students.push_back(std::make_unique<Student>());

jeśli da się konstruować Student (tutaj nie), lub...

students.push_back(std::make_unique<MathStudent>());

.. z powodu obecności przeciążonej metody..

void push_back( T&& value );

w kontenerze vector która nie będzie wołała konstruktora kopiującego dla unique_ptr bo go nie posiada oraz działania unique_ptr które przenosi wskaźniki w konstruktorach przenoszących.

Celem wprowadzenia make_unique do standardu było usunięcie ostatniego miejsca gdzie używa się "gołego new". 

komentarz 28 marca 2017 przez criss Mędrzec (172,590 p.)
edycja 28 marca 2017 przez criss

Tzn. twoim zdaniem..

std::vector<std::unique_ptr<Student>> v;
v.push_back(std::make_unique<mathStudent>());

..powinno się skompilować? Z tym się nie zgodzę. No bo.. dlaczego? std::unique_ptr<Student> i std::unique_ptr<MathStudent> to dwie różne klasy.

Co do push_back(T&& value) - co za różnica? std::unique_ptr<Student>(new MathStudent) to też rvalue, więc w przypadku mojego przykładu też zostanie zawołana push_back(T&&)

Celem wprowadzenia make_unique do standardu było usunięcie ostatniego miejsca gdzie używa się "gołego new". 

Czasami jesteśmy zmuszeni. Np. tutaj gdzie make_unique<Student> będzie próbował utworzyc obiekt Student a my chcemy MathStudent. Albo gdy chcemy, żeby nasz unique wskazywał na obiekt jakiejś stuktury, która nie ma konstruktora (niedomyslnego) i inicjalizujemy go poprzez {}.

struct A
{
   int a, b, c;
};

std::make_unique<A>(new A{1, 2, 3});

 

komentarz 28 marca 2017 przez mokrowski Mędrzec (156,260 p.)
edycja 28 marca 2017 przez mokrowski

Tak, sprawdź kompiluje się (rzecz jasna C++14..)

Co do zalet (żeby nie było że ja przekonuję): http://stackoverflow.com/questions/37514509/advantages-of-using-make-unique-over-new-operator

Co do zawołania z new, jest różnica. Odnośnik wyżej.. 

W tym przykładzie naprawdę nie ma powodu użycia new :-) Ja nie mówię że nie da się podać przykładu że będzie to konieczne. Bo to sam wiesz że zawsze się da :-) Mówimy o kawałku kodu pytającego. Dla new po C++14 w zasadzie pozostały już tylko powody typu:

1. Bo framework tego wymaga (np. Qt) i wtedy trzeba trzymać się konwencji frameworka.

2. Bo operacje są na niskim poziomie (rejestry i zabawy min. z const volatile... )

3. Jeszcze kilka naprawdę specyficznych (typu alokatory pulowe, alokatory w miejscu albo inne "cuda tworzenia")

Mi wytknięto to na code review.. stąd drążę :-)

komentarz 28 marca 2017 przez criss Mędrzec (172,590 p.)
http://coliru.stacked-crooked.com/a/e3c41bbf3d2840e7

ps: ide lulać, odpowiem jutro i link do SO też jutro zobacze
ps2: faktycznie, kompiluje się (mój błąd - dziedziczenie prywatne). Ale nie rozumiem dlaczego - wytłumaczysz?
komentarz 28 marca 2017 przez mokrowski Mędrzec (156,260 p.)
Spoko.. postaram się wrócić do tematu jutro (dziś) po 17:00.
komentarz 28 marca 2017 przez criss Mędrzec (172,590 p.)

Okej, myślę że już rozumiem. Coś mi zaskoczyło z rana, sprawdziłem i dobrze myślałem. Konstruktor (6).

komentarz 28 marca 2017 przez mokrowski Mędrzec (156,260 p.)
.. potocznie (kto to wymyślił.. chyba Mayers .. ) "universal move constructor". Ale co do autora nie jestem pewien a nie wydaje się mi to na tyle istotne żeby szukać.

Ale co do wniosków podanych w odnośniku do SO (czy używać make_unique i że .. lepsze) rozumiem że generalnie się zgadzasz?

PS. W kodzie na coliru, zapomniałeś o dziedziczeniu public. Dlatego nie chciał zbudować.
komentarz 28 marca 2017 przez criss Mędrzec (172,590 p.)

rozumiem że generalnie się zgadzasz? 

Tak, jak najbardziej.

 PS. W kodzie na coliru, zapomniałeś o dziedziczeniu public. Dlatego nie chciał zbudować.

Tak, już wczoraj dopisalem poprawkę  (ps2) do komentarza z linkiem. 

Podobne pytania

0 głosów
2 odpowiedzi 406 wizyt
pytanie zadane 12 czerwca 2017 w C i C++ przez Akiro Bywalec (2,910 p.)
+1 głos
1 odpowiedź 606 wizyt
pytanie zadane 1 kwietnia 2017 w C i C++ przez heros22pt Użytkownik (950 p.)
+1 głos
1 odpowiedź 187 wizyt

93,103 zapytań

142,076 odpowiedzi

321,560 komentarzy

62,444 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 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...