You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:55:28