【问题标题】:How can I have a list of base class objects and access derived class fields?如何获得基类对象列表并访问派生类字段?
【发布时间】:2021-11-28 19:10:07
【问题描述】:

假设我有一个基类和两个派生类:

class a {};
class b : a { int a; };
class c : a { int b; };

我有一个基类的列表,我将派生类插入到列表中:

std::list<a> list;

list.emplace_back(b());
list.emplace_back(c());

现在,我想像这样访问int a

for(auto i : list)
{
    i.a = 5;
}

我已经检查了它是什么类,但编译器仍然不允许我访问它。

如何从基类访问派生类中的任何字段?

这个问题已经被问过很多次了,但到目前为止没有一种方法对我有用。

【问题讨论】:

  • std::list&lt;a&gt; 将执行Object Slicing。没有可访问的派生字段。首先你需要一个std::list&lt;std::unique_ptr&lt;A&gt;&gt; 或类似的,从那里这个问题可能会有答案。
  • @FrançoisAndrieux 好的,我做到了,现在我得到了函数“std::unique_ptr<..etc>
  • 考虑改变你的设计——如果你想使用基类指针的容器,你还应该有虚函数而不是访问派生类的字段。

标签: c++ list c++17 std


【解决方案1】:

首先,您需要一个基类指针的列表,否则在将它们插入列表时会slice the objects

然后,您需要根据需要对指针进行类型转换以访问派生类。

如果所有列表元素都指向同一个派生类型,则可以使用static_cast

struct A {};
struct B : A { int a; };
struct C : A { int b; };

std::list<std::unique_ptr<A>> lst;

lst.push_back(std::make_unique<B>());
lst.push_back(std::make_unique<B>());

for(auto &ptr : lst)
{
    static_cast<B*>(ptr.get())->a = 5;
}

否则,请改用dynamic_cast 在访问其字段之前测试派生类类型:

struct A {};
struct B : A { int a; };
struct C : A { int b; };

std::list<std::unique_ptr<A>> lst;

lst.push_back(std::make_unique<B>());
lst.push_back(std::make_unique<C>());

for(auto &ptr : lst)
{
    B *b = dynamic_cast<B*>(ptr.get());
    if (b)
        b->a = 5;
}

【讨论】:

  • 免责声明:本文作者若因支付运行时多态性的成本而没有任何明显优势所造成的损害,作者概不负责
  • 真的很感激,我很惊讶在所有问过这个问题的人中没有人给出这个答案
  • @MatG 当然,应该使用多态性来抽象出这样的细节,但也有想要访问特定字段的有效用例。我们在这里分享知识并回答有关如何做特定事情的问题。当然,也可以提出更好的选择。
  • @MaxCE 有很多关于 SO 的问题的答案证明了使用多态性和类型转换指针来访问派生类。只是当按照预期的方式使用多态性时,你不应该需要首先这样做。
  • @RemyLebeau 开个小玩笑,你严格回答了问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 2015-02-25
  • 1970-01-01
  • 2013-08-16
  • 2013-02-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多