Ինչու՞ վեկտորը վատ կաշխատի, եթե նրանից ժառանգվի։
sobes.tech AI
Պատասխան AI-ից
Նվագելությունը std::vector-ից չի առաջարկվում՝ դրա վիրտուալ դեստրուկտորների և այլ վիրտուալ ֆունկցիաների բացակայության պատճառով, ինչը խախտում է LSP (Լիսկովի փոխարինման սկզբունքը) և հանգեցնում է պոլիմորֆիկ օգտագործման խնդիրների:
Օրինակներ՝
-
Կտրում (slicing) խնդիր: Երբ փոխանցում եք ժառանգական դասի օբյեկտը արժեքով կամ հղումով բազային դասին
std::vector, ժառանգական դասի հատուկ տվյալներն ու վարքագիծը կկորցվեն:#include <vector> #include <iostream> class MyVector : public std::vector<int> { public: int my_data = 100; // Վիրտուալ դեստրուկտոր չպետք է լինի ~MyVector() { std::cout << "MyVector դեստրուկտոր" << std::endl; } }; void process_vector(std::vector<int> vec) { // Վերցվում է արժեքով - տեղի է ունենում կտրում // MyVector դեստրուկտորը չի կանչվի std::cout << "std::vector մշակումը" << std::endl; } int main() { MyVector mv; mv.push_back(1); process_vector(mv); // Կատարվում է MyVector օբյեկտի կտրում return 0; } // Այստեղ միայն std::vector դեստրուկտորը կկանչվի -
Վիրտուալ դեստրուկտորի բացակայություն: Եթե ժառանգական դասի օբյեկտը ջնջում եք բազային դասի հղումով
std::vector, ժառանգական դասի դեստրուկտորը չի կանչվի, ինչը կարող է հանգեցնել ռեսուրսների արտահոսքի:#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 կոնստրուկտոր" << std::endl; } // Վիրտուալ դեստրուկտոր չպետք է լինի ~DerivedVector() { std::cout << "DerivedVector դեստրուկտոր" << std::endl; delete resource; // Չի կանչվի } }; int main() { // Ջնջում բազային դասի հղումով std::vector<int>* base_ptr = new DerivedVector(); // delete base_ptr - միայն std::vector դեստրուկտորը կկանչվի, // DerivedVector դեստրուկտորը չի կանչվի, ռեսուրսի արտահոսք delete base_ptr; // Օրինակ with unique_ptr // std::unique_ptr<std::vector<int>> up = std::make_unique<DerivedVector>(); // up->push_back(5); // Երբ unique_ptr- ի տիրույթից դուրս է գալիս, նա կանչում է delete- ը base_ptr- ի վրա: // Սա համարժեք է delete base_ptr- ին և կարող է հանգեցնել նույն խնդրին, եթե vector- ը չունի վիրտուալ դեստրուկտոր return 0; } // Հիշողությունը, որը հատկացվել է resource- ի համար, չի ազատվի -
Կոնստրուկտորներ:
std::vector-ի կոնստրուկտորների (օրինակ, պատճենահավաք, տեղափոխում) վարքը կարող է չհամապատասխանել սպասումներին ժառանգական դասի համար, եթե այն ավելացնում է սեփական վիճակ կամ լոգիկա:
Դեպի std::vector-ից ժառանգվելու փոխարեն, ավելի լավ է կիրառել՝
- Կոմպոզիցիա: Օգտագործել
std::vectorորպես դասի անդամ: Դա թույլ է տալիս վերահսկել ինտերֆեյսը և վարքը, օգտագործելովstd::vector-ը ներսում:#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 { // Հասանելիություն տալու համար return data; } // MyContainer դեստրուկտորը ճիշտ կանչում է data- ի դեստրուկտորը ~MyContainer() { std::cout << "MyContainer դեստրուկտոր" << std::endl; } }; int main() { MyContainer mc; mc.add(1); std::cout << "Տվյալների չափը: " << mc.get_data().size() << std::endl; return 0; } // MyContainer դեստրուկտորը կանչվում է, որը իր հերթին կանչում է std::vector- ի դեստրուկտորը - Ազատ ֆունկցիաներ և ալգորիթմներ: Հեշտացնել
std::vector-ի գործառույթները սովորական ֆունկցիաներով կամ օգտագործել ստանդարտ ալգորիթմները:
Այս մոտեցումները ավելի ճկուն, անվտանգ և համապատասխանում են OOP և C++ գրադարանների նախագծման սկզբունքներին: Ստանդարտ կոնտեյներները նախատեսված չեն որպես բազային դասեր օգտագործելու համար։