Kāpēc vektors slikti darbosies, ja no tā manto?
sobes.tech AI
Atbilde no AI
Mantošana no std::vector nav ieteicama, jo trūkstamu virtuālo destruktora un citām virtuālām funkcijām, kas pārkāpj LSP (Liskova aizvietošanas princips) un izraisa problēmas polimorfiskā lietošanā.
Piemēri:
-
Sagriešanas (slicing) problēma: Kad pārsūtāt mantojošas klases objektu ar vērtības vai atsauces palīdzību uz bāzes klasi
std::vector, mantojošās klases specifiskie dati un uzvedība tiks zaudēti.#include <vector> #include <iostream> class MyVector : public std::vector<int> { public: int my_data = 100; // Bez virtuāla destruktora ~MyVector() { std::cout << "MyVector destruktors" << std::endl; } }; void process_vector(std::vector<int> vec) { // Pieņem ar vērtību - notiek sagriešana // MyVector destruktors netiks izsaukts std::cout << "std::vector apstrāde" << std::endl; } int main() { MyVector mv; mv.push_back(1); process_vector(mv); // Notiek MyVector objekta sagriešana return 0; } // Šeit tiks izsaukts tikai std::vector destruktors -
Trūkst virtuāla destruktora: Ja dzēšat mantojošas klases objektu ar atsauci uz bāzes klasi
std::vector, mantojošā klases destruktors netiks izsaukts, kas var novest pie resursu noplūdes.#include <vector> #include <iostream> #include <memory> // unique_ptr class DerivedVector : public std::vector<int> { public: int* resource; DerivedVector() : std::vector<int>(), resource(new int) { std::cout << "DerivedVector konstruktors" << std::endl; } // Bez virtuāla destruktora ~DerivedVector() { std::cout << "DerivedVector destruktors" << std::endl; delete resource; // Var netikt izsaukts } }; int main() { // Dzēšana ar bāzes klases atsauci std::vector<int>* base_ptr = new DerivedVector(); // delete base_ptr - tiks izsaukts tikai std::vector destruktors, // DerivedVector destruktors netiks izsaukts, notiks resursu noplūde delete base_ptr; // Piemērs ar unique_ptr // std::unique_ptr<std::vector<int>> up = std::make_unique<DerivedVector>(); // up->push_back(5); // Kad unique_ptr iziet no darbības apgabala, tas izsauks delete uz pointer base_ptr. // Tas ir ekvivalents ar delete base_ptr; un var novest pie tā paša problēmas, ja vector nav virtuāls destruktors. return 0; } // Atbrīvotā resursa atmiņa netiks brīvi atbrīvota -
Konstruktori:
std::vectorkonstruktori (piemēram, kopēšanas, pārvietošanas) var neatbilst gaidām mantojošā klases vajadzībām, ja tas pievieno savu stāvokli vai loģiku.
Vietā, lai mantošanas no std::vector, labāk ir:
- Kompozīcija: Izmantot
std::vectorkā klases locekli. Tas ļauj kontrolēt saskarni un uzvedību, izmantojotstd::vectoriekšpusē.#include <vector> #include <iostream> class MyContainer { private: std::vector<int> data; int my_extra_data = 100; public: void add(int val) { data.push_back(val); } const std::vector<int>& get_data() const { // Nodrošināt piekļuvi vektoram return data; } // MyContainer destruktors pareizi izsauks data destruktora ~MyContainer() { std::cout << "MyContainer destruktors" << std::endl; } }; int main() { MyContainer mc; mc.add(1); std::cout << "Datu lielums: " << mc.get_data().size() << std::endl; return 0; } // MyContainer destruktors tiks izsaukts, kas savukārt izsauks std::vector destruktora - Brīvas funkcijas un algoritmi: Paplašināt
std::vectorfunkcionalitāti ar parastām funkcijām vai izmantot standartus algoritmus.
Šie pieejas ir elastīgāki, drošāki un atbilst OOP un bibliotēku projektēšanas principiem. Standarta konteineri nav paredzēti kā bāzes klases.