C++ 共享指针的子类向基类的共享指针的向量。

huangapple go评论78阅读模式
英文:

C++ Vector of shared_ptr of child to vector of shared_ptr to base

问题

I have this class:

class GameObjectTemplateModel : public DatabaseModel<GameObjectTemplate, WorldDatabaseConnection, GameObjectTemplateModel>;

And I have this:

std::vector<std::shared_ptr<DatabaseModel>> ManyWhere(const std::string& column, const std::string& where);

and this:

std::vector<std::shared_ptr<GameObjectTemplateModel>> LootableCollection;

Why I cannot do:

LootableCollection = ManyWhere("test","test");

My question is how can I make the vector of child shared_ptrs to get its data from the vector of base shared ptr?

Is it a good idea if I use dynamic_cast?

英文:

I have this class

class GameObjectTemplateModel : public DatabaseModel&lt;GameObjectTemplate, WorldDatabaseConnection, GameObjectTemplateModel&gt;

And I have this:

std::vector&lt;std::shared_ptr&lt;DatabaseModel&gt;&gt;  ManyWhere(const std::string&amp; column, const std::string&amp; where);

and this:

std::vector&lt;std::shared_ptr&lt;GameObjectTemplateModel&gt;&gt; LootableCollection;

Why I can not do:

LootableCollection = ManyWhere(&quot;test&quot;,&quot;test&quot;);

My question is how can I make the vector of child shared_ptrs to get it's data from vector of base shared ptr?

Is it good idea if I use dynamic_cast ?

答案1

得分: 1

Sure, here are the translated parts:

My question is how can I make the vector of child shared_ptrs to get its data from the vector of base shared ptr?

问题是如何使子 shared_ptr 的向量从基本 shared ptr 的向量中获取数据?

You need to have something that will convert each pointer in turn. In C++23 that can be a view like std::ranges::to<std::vector>.

你需要有一些东西,依次转换每个指针。在C++23中,可以使用类似 std::ranges::to<std::vector> 的视图。

LootableCollection = ManyWhere("test","test") | std::ranges::tostd::vector;

LootableCollection = ManyWhere("test","test") | std::ranges::tostd::vector;

Prior to that you could use the iterator assignment (with a helper variable)

在那之前,您可以使用迭代器赋值(使用辅助变量)

auto collection = ManyWhere("test","test");
LootableCollection.assign(collection.begin(), collection.end());

auto collection = ManyWhere("test","test");
LootableCollection.assign(collection.begin(), collection.end());

Is it a good idea if I use dynamic_cast?

如果我使用 dynamic_cast 是一个好主意吗?

No. Using a pointer gotten via dynamic_cast is undefined behavior in almost all cases, and this isn't one of the exceptions.

不是的。几乎在所有情况下,使用通过 dynamic_cast 获取的指针都是未定义行为,而这不是其中的一个例外。

The type std::vector<std::shared_ptr<GameObjectTemplateModel>> is not related to the type std::vector<std::shared_ptr<DatabaseModel>> at all, despite the types GameObjectTemplateModel and DatabaseModel being related.

类型 std::vector<std::shared_ptr<GameObjectTemplateModel>> 与类型 std::vector<std::shared_ptr<DatabaseModel>> 完全无关,尽管类型 GameObjectTemplateModelDatabaseModel 有关。

英文:

> My question is how can I make the vector of child shared_ptrs to get it's data from vector of base shared ptr?

You need to have something that will convert each pointer in turn. In C++23 that can be a view like std::ranges::to&lt;std::vector&gt;.

LootableCollection = ManyWhere(&quot;test&quot;,&quot;test&quot;) | std::ranges::to&lt;std::vector&gt;;

Prior to that you could use the iterator assignment (with a helper variable)

auto collection = ManyWhere(&quot;test&quot;,&quot;test&quot;);
LootableCollection.assign(collection.begin(), collection.end());

> Is it good idea if I use dynamic_cast ?

No. Using a pointer gotten via dynamic_cast is undefined behaviour in almost all cases, and this isn't one of the exceptions.

The type std::vector&lt;std::shared_ptr&lt;GameObjectTemplateModel&gt;&gt; is not related to the type std::vector&lt;std::shared_ptr&lt;DatabaseModel&gt;&gt; at all, despite the types GameObjectTemplateModel and DatabaseModel being related.

答案2

得分: 1

以下是您要翻译的内容:

问题在于,即使有一种方法可以在向量的元素类型之间进行转换,这并不会建立向量类型与赋值运算符/构造函数之间的关系,这些赋值/初始化所需的运算符/构造函数并不存在。

您需要为此提供自己的转换。取决于您是否确定元素的类型是否正确,您应该使用std::static_pointer_caststd::dynamic_pointer_cast 进行元素转换:

以下示例将Base用作基类,Derived用作派生类,以简化问题,并假设std::vector&lt;std::shared_ptr&lt;Base&gt;&gt;的所有元素实际上引用Derived

struct Base
{
    virtual ~Base() = default;
};

struct Derived : Base
{
};

template&lt;class T, class U&gt;
std::vector&lt;std::shared_ptr&lt;T&gt;&gt; ConvertSharedPointerVector(std::vector&lt;std::shared_ptr&lt;U&gt;&gt;&amp;&amp; from)
{
    std::vector&lt;std::shared_ptr&lt;T&gt;&gt; to;
    to.reserve(from.size());

    for (auto&amp; e : from)
    {
        to.emplace_back(std::static_pointer_cast&lt;T&gt;(std::move(e)));
    }

    return to;
}

std::vector&lt;std::shared_ptr&lt;Base&gt;&gt; Create()
{
    return { std::make_shared&lt;Derived&gt;(), std::make_shared&lt;Derived&gt;() };
}

int main()
{
    std::vector&lt;std::shared_ptr&lt;Derived&gt;&gt; convertedVector = ConvertSharedPointerVector&lt;Derived&gt;(Create());
}

注意:最好避免这种类型的转换。您可以尝试使用模板来处理这个问题。

英文:

The problem here is that even though there may be a way of converting between element types of the vectors, this doesn't establish a relationship between the vector types and the assigment operators/constructors necessary for the assignment/initialization to work do not exist.

You need to provide your own conversion for this. Depending on whether you're sure the types of the elements are ok or not, you should be using std::static_pointer_cast or std::dynamic_pointer_cast for the element conversions:

The following example uses Base as base class and Derived as derived class for simplicity and assumes all elements of the std::vector&lt;std::shared_ptr&lt;Base&gt;&gt; actually reference Deriveds.

struct Base
{
    virtual ~Base() = default;
};

struct Derived : Base
{
};

template&lt;class T, class U&gt;
std::vector&lt;std::shared_ptr&lt;T&gt;&gt; ConvertSharedPointerVector(std::vector&lt;std::shared_ptr&lt;U&gt;&gt;&amp;&amp; from)
{
    std::vector&lt;std::shared_ptr&lt;T&gt;&gt; to;
    to.reserve(from.size());

    for (auto&amp; e : from)
    {
        to.emplace_back(std::static_pointer_cast&lt;T&gt;(std::move(e)));
    }

    return to;
}

std::vector&lt;std::shared_ptr&lt;Base&gt;&gt; Create()
{
    return { std::make_shared&lt;Derived&gt;(), std::make_shared&lt;Derived&gt;() };
}

int main()
{
    std::vector&lt;std::shared_ptr&lt;Derived&gt;&gt; convertedVector = ConvertSharedPointerVector&lt;Derived&gt;(Create());
}

Note: You're likely better of avoiding this kind of conversion. You may be able to use templates for this.

huangapple
  • 本文由 发表于 2023年5月18日 00:36:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76274337.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定