如何在C++中无需继承将B类对象存入A类指针向量?
无需继承的多类型存储方案(针对A、B类)
首先明确:绝对不能直接把B*强制转换为A*存入原向量,这属于C++标准里的未定义行为,会导致程序崩溃或不可预期的错误。下面是几种安全的替代方案:
方案1:使用std::variant(C++17及以上)
这是类型安全的多类型存储方式,专门用来处理这种需要存储不同类型对象的场景。把原向量的类型改成std::vector<std::variant<A*, B*>>,就能同时存放A和B的指针。
示例代码:
#include <vector> #include <variant> #include <iostream> class A { public: A() {/*...*/} void sayA() { std::cout << "I'm A\n"; } }; class B { public: B() {/*...*/} void sayB() { std::cout << "I'm B\n"; } }; int main() { std::vector<std::variant<A*, B*>> objects; // 添加A和B的对象指针 objects.emplace_back(new A()); objects.emplace_back(new B()); // 遍历访问元素 for (auto& var : objects) { // 使用std::visit处理不同类型 std::visit([](auto ptr) { using T = std::decay_t<decltype(ptr)>; if constexpr (std::is_same_v<T, A*>) { ptr->sayA(); } else if constexpr (std::is_same_v<T, B*>) { ptr->sayB(); } }, var); } // 记得释放内存(或者用智能指针更安全) for (auto& var : objects) { std::visit([](auto ptr) { delete ptr; }, var); } return 0; }
如果不想手动管理内存,可以把指针换成std::unique_ptr<A>和std::unique_ptr<B>,变体类型改成std::variant<std::unique_ptr<A>, std::unique_ptr<B>>,避免内存泄漏。
方案2:使用void*通用指针(不推荐,仅作参考)
void*可以存储任意类型的指针,但会丢失类型信息,需要额外记录每个元素的类型,访问时手动强制转换,风险较高(容易因类型转换错误导致崩溃)。
示例代码:
#include <vector> #include <iostream> enum class ObjectType { A_TYPE, B_TYPE }; class A { public: A() {/*...*/} void sayA() { std::cout << "I'm A\n"; } }; class B { public: B() {/*...*/} void sayB() { std::cout << "I'm B\n"; } }; int main() { std::vector<void*> objects; std::vector<ObjectType> types; // 额外记录每个元素的类型 // 添加对象 objects.push_back(new A()); types.push_back(ObjectType::A_TYPE); objects.push_back(new B()); types.push_back(ObjectType::B_TYPE); // 访问元素 for (size_t i = 0; i < objects.size(); ++i) { if (types[i] == ObjectType::A_TYPE) { static_cast<A*>(objects[i])->sayA(); } else if (types[i] == ObjectType::B_TYPE) { static_cast<B*>(objects[i])->sayB(); } } // 释放内存 for (size_t i = 0; i < objects.size(); ++i) { if (types[i] == ObjectType::A_TYPE) { delete static_cast<A*>(objects[i]); } else { delete static_cast<B*>(objects[i]); } } return 0; }
方案3:自定义包装类
自己写一个包装类,内部封装A或B的指针,通过成员函数提供安全的访问接口,本质是手动实现std::variant的简化版本,适合C++17以下的环境。
示例代码:
#include <vector> #include <iostream> class A { public: A() {/*...*/} void sayA() { std::cout << "I'm A\n"; } }; class B { public: B() {/*...*/} void sayB() { std::cout << "I'm B\n"; } }; class ObjectWrapper { public: ObjectWrapper(A* a_ptr) : type_(Type::A), a_ptr_(a_ptr) {} ObjectWrapper(B* b_ptr) : type_(Type::B), b_ptr_(b_ptr) {} // 提供访问方法 void callFunc() { if (type_ == Type::A) { a_ptr_->sayA(); } else { b_ptr_->sayB(); } } // 析构函数释放内存 ~ObjectWrapper() { if (type_ == Type::A) { delete a_ptr_; } else { delete b_ptr_; } } private: enum class Type { A, B }; Type type_; union { A* a_ptr_; B* b_ptr_; }; }; int main() { std::vector<ObjectWrapper> objects; objects.emplace_back(new A()); objects.emplace_back(new B()); for (auto& wrapper : objects) { wrapper.callFunc(); } return 0; }
注意:上面的包装类用了union来节省内存,也可以用两个成员变量加空值判断,逻辑更简单但内存开销略大。
内容的提问来源于stack exchange,提问作者yees_7
相关产品推荐
相关产品推荐

