如何获得基类对象列表并访问派生类字段?

How can I have a list of base class objects and access derived class fields?

提问人:MaxCE 提问时间:10/9/2021 最后编辑:Remy LebeauMaxCE 更新时间:10/9/2021 访问量:864

问:

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

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;
}

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

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

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

C++ 列表 C++17 标准

评论

4赞 François Andrieux 10/9/2021
std::list<a>将执行对象切片。没有可访问的派生字段。首先你需要一个或类似的,从那里这个问题可能会有一个答案。std::list<std::unique_ptr<A>>
0赞 MaxCE 10/9/2021
@FrançoisAndrieux好的,我这样做了,现在我得到了函数“std::unique_ptr<..etc“不能被引用 -- 它是一个已删除的函数
1赞 Eugene 10/9/2021
考虑更改您的设计 - 如果要使用基类指针的容器,则还应该具有虚函数,而不是访问派生类的字段。

答:

1赞 Remy Lebeau 10/9/2021 #1

首先,您需要一个基类指针列表,否则在将对象插入到列表中时,将对对象进行切片

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

如果所有列表元素都指向同一派生类型,则可以使用: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;
}

评论

0赞 MatG 10/9/2021
免责声明:如果本文作者不对因支付运行时多态性成本而造成的损失负责,没有任何明显的优势
0赞 MaxCE 10/9/2021
真的很感激这一点,我很惊讶在所有问过这个问题的人中,没有人给出这个答案
0赞 Remy Lebeau 10/9/2021
@MatG 诚然,应该使用多态性来抽象出这样的细节,但也有想要访问特定字段的有效用例。我们在这里分享知识并回答有关如何做特定事情的问题。当然,也要提出更好的选择。
0赞 Remy Lebeau 10/9/2021
@MaxCE SO 上有很多问题,这些问题的答案演示了使用多态性和类型转换指针来访问派生类。只是当按照预期的方式使用多态性时,您首先不需要这样做。
0赞 MatG 10/10/2021
@RemyLebeau那是个小玩笑,你严格地回答了这个问题