gpt4 book ai didi

c++ - 当子级存储在基指针 vector 上时如何从基类动态转换为子类

转载 作者:太空宇宙 更新时间:2023-11-04 16:01:51 28 4
gpt4 key购买 nike

我已将 Child 对象的共享指针存储在 Vector of Base shared pointers 中,我需要将 Base vector 的元素动态转换为其子对象类型,这样我就可以调用带有 child 特定签名的函数

下面是一个例子。第一个代码块定义了类层次结构和我想使用的“识别”函数。第二个代码块给出了一个具体示例,说明我想如何调用特定于 TYPE 的“识别”函数,前提是我可以将原始对象类型从 Base 类转换为 Child 类(例如 A ,B,C).

有什么模式或技术可以解决这个问题吗?

#include <iostream>
#include <memory>
#include <vector>

class Base {};
class A : public Base{};
class B : public Base{};
class C : public Base{};

class CollectionOfBase
{
public:
void add (std::shared_ptr<Base> item){m_items.push_back(item);}
std::vector<std::shared_ptr<Base>> const& getItems() const {return m_items;}

private:
std::vector<std::shared_ptr<Base>> m_items;
};

// I want to use these 3 functions instead of identify( std::shared_ptr<Base> const& )
void identify( std::shared_ptr<A> const& )
{
std::cout << "A" << std::endl;
}
void identify( std::shared_ptr<B> const& )
{
std::cout << "B" << std::endl;
}
void identify( std::shared_ptr<C> const& )
{
std::cout << "C" << std::endl;
}

//This function works in the below for loop, but this is not what I need to use
void identify( std::shared_ptr<Base> const& )
{
std::cout << "Base" << std::endl;
}

在下面,您可以找到第二个代码块:

int main()
{
using namespace std;

CollectionOfBase collection;

collection.add(make_shared<A>());
collection.add(make_shared<A>());
collection.add(make_shared<C>());
collection.add(make_shared<B>());

for (auto const& x : collection.getItems())
{
// THE QUESTION:
// How to distinguish different type of items
// to invoke "identify" with object specific signatures (e.g. A,B,C) ???
// Can I cast somehow the object types that I push_back on my Collection ???
// Note that this loop does not know the add order AACB that we pushed the Child pointers.

identify(x);
}
/*
The desired output of this loop should be:

A
A
C
B

*/

return 0;
}

代码也可以在 Ideone 上找到.

最佳答案

您可以在这里采用三种方法:OO 和动态分派(dispatch)、访问者和变体。哪一个更好将取决于您拥有多少类型和您拥有多少操作 - 以及您更有可能添加到哪一个。

  1. 实际使用 OO。如果您需要每个派生对象以不同的方式执行某些操作,那么在 OO 中执行此操作的方法是添加一个虚拟成员函数:

    struct Base { virtual const char* name() = 0; };
    struct A : Base { const char* name() override { return "A"; }
    // ...

    for (auto const& x : collection.getItems()) {
    std::cout << x->name() << std::endl;
    }
  2. 使用访客模式。这是 OO 和函数式之间的一半——我们创建了一个知道如何与所有类型交互的基础对象:

    struct Visitor;
    struct Base { virtual void visit(Visitor& ) = 0; };
    struct A;
    struct B;
    struct C;

    struct Visitor {
    virtual void visit(A& ) = 0;
    virtual void visit(B& ) = 0;
    virtual void visit(C& ) = 0;
    };

    struct A : Base { void visit(Visitor& v) override { v.visit(*this); } };
    // ...

    struct IdentityVisitor : Visitor {
    void visit(A& ) { std::cout << "A" << std::endl; }
    void visit(B& ) { std::cout << "B" << std::endl; }
    void visit(C& ) { std::cout << "C" << std::endl; }
    };

    IdentityVisitor iv;
    for (auto const& x : collection.getItems()) {
    x->visit(iv);
    }
  3. 只需使用一个变体。而不是存储 shared_ptr<Base> 的集合, 存储 variant<A,B,C> 的集合这些类型甚至不在层次结构中。它们只是三种任意类型。然后:

    for (auto const& x : collection.getItems()) {
    visit(overload(
    [](A const& ){ std::cout << "A" << std::endl; },
    [](B const& ){ std::cout << "B" << std::endl; },
    [](C const& ){ std::cout << "C" << std::endl; }
    ), x);
    }

关于c++ - 当子级存储在基指针 vector 上时如何从基类动态转换为子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42470640/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com