C++:存储接口对象的vector中访问std::string_view出现未定义行为的解决方法
问题原因分析
你遇到的问题核心是基类与派生类的name成员属于独立变量,并未实现多态覆盖:C++中,当派生类声明了和基类同名的成员变量时,只会隐藏基类的成员,而非重写。因此通过IFoo*指针访问name时,实际读取的是基类IFoo中默认初始化的空std::string_view,而非派生类的"bar"值。
解决方案
最符合面向接口设计的方案是将name改为虚函数,利用C++多态机制实现正确的成员访问:
#include <string_view> #include <vector> #include <iostream> struct IFoo { public: virtual ~IFoo() = default; // 定义纯虚函数,强制派生类提供实现 virtual std::string_view name() const = 0; }; struct Foo : public IFoo { public: // 重写基类虚函数,返回固定字符串字面量 std::string_view name() const override { return "bar"; } }; // 扩展其他派生类示例 struct AnotherFoo : public IFoo { std::string_view name() const override { return "another_foo"; } }; int main() { std::vector<IFoo*> foos; Foo* foo = new Foo(); std::cout << "Name of object before storing: " << foo->name() << std::endl; foos.push_back(new Foo()); foos.push_back(new AnotherFoo()); for (auto ptr : foos) { std::cout << "Name of object after storing: " << ptr->name() << std::endl; } // 手动释放内存避免泄漏 delete foo; for (auto ptr : foos) { delete ptr; } }
方案说明
- 虚函数是C++多态的核心,通过基类指针调用时,会自动匹配实际指向的派生类重写版本,保证访问到正确的
name值。 - 字符串字面量的生命周期贯穿整个程序运行期,因此返回
std::string_view不会出现悬空引用问题,完全满足你"name在实例化前已确定"的需求。
备选方案(非虚函数实现)
如果不想使用虚函数,也可以通过基类构造函数传递name值,让派生类在构造时初始化基类成员:
#include <string_view> #include <vector> #include <iostream> struct IFoo { public: const std::string_view name; explicit IFoo(std::string_view n) : name(n) {} virtual ~IFoo() = default; }; struct Foo : public IFoo { public: Foo() : IFoo("bar") {} }; int main() { std::vector<IFoo*> foos; Foo* foo = new Foo(); std::cout << "Name of object before storing: " << foo->name << std::endl; foos.push_back(new Foo()); for (auto ptr : foos) { std::cout << "Name of object after storing: " << ptr->name << std::endl; } delete foo; for (auto ptr : foos) { delete ptr; } }
这种方式的缺点是灵活性较低,每个派生类都需要编写构造函数传递name值,且无法动态修改name(若有此类需求)。
内容的提问来源于stack exchange,提问作者Frogieder
相关产品推荐
相关产品推荐

