C++跨类访问基类指针vector中派生类对象触发访问违规问题
问题核心原因
你遇到的访问错误本质是悬空指针问题:
- 你在
case 'a'的局部作用域里定义了栈对象StarterFood tmpStarter,这个对象的生命周期仅在当前case的大括号范围内,出了大括号后就会被自动销毁 - 你把这个栈对象的地址存入vector,返回给main函数后,vector里存储的全是已经失效的指针,访问时就会触发0xCCCCCCCC的越界错误(0xCCCCCCCC是VC++编译器对已销毁栈内存的标记值)
解决方案
方案1:使用堆分配原生指针(不推荐,需要手动释放内存避免泄漏)
修改cM函数里的对象创建逻辑,用new在堆上分配派生类对象:
vector<Item*> Items::cM() { vector<Item*> M; string line; string filePath = "..."; ifstream stream(filePath); while (getline(stream, line)) { vector <string> IV= UtilFunctions::splitString(line, ','); const char *t= IV[0].c_str(); switch (*t) { case 'a': { // 改为堆上分配,生命周期由你自己控制 Item* b = new StarterFood(*a,b,c); M.push_back(b); break; } // 其他派生类case同理 } } return M; }
注意:使用完vector后需要遍历调用
delete释放所有元素,避免内存泄漏。
方案2:使用unique_ptr智能指针(推荐,自动管理内存,无泄漏风险)
你之前用unique_ptr报错是因为没有正确构造,正确写法如下:
首先修改函数返回值类型为vector<unique_ptr<Item>>:
vector<unique_ptr<Item>> Items::cM() { vector<unique_ptr<Item>> M; string line; string filePath = "..."; ifstream stream(filePath); while (getline(stream, line)) { vector <string> IV= UtilFunctions::splitString(line, ','); const char *t= IV[0].c_str(); switch (*t) { case 'a': { // 用std::make_unique构造unique_ptr M.push_back(std::make_unique<StarterFood>(*a,b,c)); break; } // 其他派生类case同理 } } return M; }
main函数对应修改为:
int main(){ auto items = Items::cM(); items[0]->toString(); // 正常调用派生类重载方法,不会出现对象切片 system("pause"); return 0; }
注意:需要保证基类
Item有虚析构函数,否则智能指针释放内存时可能出现未定义行为,基类定义需要加:class Item { public: virtual ~Item() = default; virtual std::string toString() const = 0; // 虚函数保证派生类重载生效 // 其他基类逻辑 };
补充说明
你之前解引用指针出现对象切片,是因为你把派生类对象直接赋值给了基类对象,只要始终用基类指针/智能指针存储、调用虚函数,就不会出现切片问题。智能指针可以正常在不同类之间传递/移动,不需要额外做特殊处理。
内容的提问来源于stack exchange,提问作者David Benz
相关产品推荐
相关产品推荐

