Waarom zal de vector slecht werken als er van wordt geërfd?
sobes.tech AI
Antwoord van AI
Erfelijkheid van std::vector wordt niet aanbevolen vanwege het ontbreken van virtuele destructors en andere virtuele functies, wat de LSP (Liskov Substitutie Principe) schendt en problemen veroorzaakt bij polymorf gebruik.
Voorbeelden van problemen:
-
Slicing-probleem: Bij het doorgeven van een object van een afgeleide klasse via waarde of referentie naar de basisklasse
std::vector, gaan gegevens en gedrag die specifiek zijn voor de afgeleide klasse verloren.#include <vector> #include <iostream> class MyVector : public std::vector<int> { public: int my_data = 100; // Zonder virtuele destructor ~MyVector() { std::cout << "MyVector destructor" << std::endl; } }; void process_vector(std::vector<int> vec) { // Ontvangt per waarde - slicing vindt plaats // Destructor van MyVector wordt niet aangeroepen std::cout << "Processing std::vector" << std::endl; } int main() { MyVector mv; mv.push_back(1); process_vector(mv); // Slicing van MyVector object return 0; } // Alleen std::vector destructor wordt aangeroepen -
Ontbreken van virtuele destructor: Als je een object van een afgeleide klasse verwijdert via een pointer naar de basisklasse
std::vector, wordt de destructor van de afgeleide klasse niet aangeroepen, wat kan leiden tot resource leaks.#include <vector> #include <iostream> #include <memory> // Voor unique_ptr class DerivedVector : public std::vector<int> { public: int* resource; DerivedVector() : std::vector<int>(), resource(new int) { std::cout << "DerivedVector constructor" << std::endl; } // Ontbreekt virtuele destructor ~DerivedVector() { std::cout << "DerivedVector destructor" << std::endl; delete resource; // Mogelijk niet aangeroepen } }; int main() { // Verwijdering via pointer naar basisklasse std::vector<int>* base_ptr = new DerivedVector(); // Bij delete base_ptr wordt alleen std::vector destructor aangeroepen, // destructor van DerivedVector wordt niet aangeroepen, resource leaking delete base_ptr; // Voorbeeld met unique_ptr // std::unique_ptr<std::vector<int>> up = std::make_unique<DerivedVector>(); // Bij het verlaten van scope roept unique_ptr delete aan op de raw pointer base_ptr. // Dit is gelijk aan delete base_ptr; en leidt tot hetzelfde probleem als vector geen virtuele destructor heeft. return 0; } // Geheugen voor resource wordt niet vrijgegeven -
Constructors: Het gedrag van constructors van
std::vector(bijvoorbeeld kopieer- en move-constructors) kan niet voldoen aan de verwachtingen voor een afgeleide klasse als deze eigen toestand of logica toevoegt.
In plaats van te erven van std::vector, zijn de beste benaderingen:
- Samenstelling: Gebruik
std::vectorals lid van een klasse. Dit stelt je in staat om de interface en het gedrag van de nieuwe klasse te controleren, doorstd::vectorbinnenin te gebruiken.#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 { // Toegang tot vector indien nodig return data; } // Destructor van MyContainer roept correct destructor van data aan ~MyContainer() { std::cout << "MyContainer destructor" << std::endl; } }; int main() { MyContainer mc; mc.add(1); std::cout << "Data size: " << mc.get_data().size() << std::endl; return 0; } // Destructor van MyContainer wordt aangeroepen, die op zijn beurt destructor van std::vector aanroept - Vrije functies en algoritmen: Breid functionaliteit van
std::vectoruit met gewone functies of gebruik standaard algoritmen.
Deze benaderingen zijn flexibeler, veiliger en voldoen aan de principes van OOP en bibliotheekontwerp in C++. Standaard containers zijn niet bedoeld om als basisklassen te worden gebruikt.