首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从异构std::list检索数据

从异构std::list检索数据
EN

Stack Overflow用户
提问于 2013-04-03 19:31:16
回答 4查看 682关注 0票数 1

在下面的代码中,我只是尝试尝试使用一个异构的std::list,其中我将三个派生类对象存储在一个Base*类型的列表中。当从列表中检索数据时,我遇到了一些问题。我该怎么做?以下代码之所以有效,是因为这三个类在定义上都是相同的。所以编译器设法给了我预期的输出。

代码语言:javascript
运行
复制
#include <list>
#include <iostream>
#include <string.h>

class Base;
typedef std::list<Base*> any_list;

class Base{};

class Derived1 : public Base
{
public:
    std::string s;
    Derived1():s("D1"){}
};
class Derived2 : public Base
{
public:
    std::string s;
    Derived2():s("D2"){}
};
class Derived3 : public Base
{
public:
    std::string s;
    Derived3():s("D3"){}
};

int main(int argc, char **argv) {
    any_list l;
    l.push_back(new Derived1);
    l.push_back(new Derived2);
    l.push_back(new Derived3);

    for(any_list::iterator itr=l.begin();itr!=l.end();++itr)
        std::cout<<((Derived1*)*itr)->s;
}

请注意,交货单是-

D1 D2 D3

现在,如果我在任何类中添加一个额外的成员(这是预期的和正确的),这是行不通的。那么,我应该如何键入数据并从异构列表中检索数据呢?我是不是漏掉了什么?

EN

回答 4

Stack Overflow用户

发布于 2013-04-03 19:38:35

最简单的方法可能是像这样定义Base:

代码语言:javascript
运行
复制
class Base {
public:
    virtual const std::string& getData() = 0;
}

然后让您的各种派生类适当地实现getData()。这样,输出循环就可以是:

代码语言:javascript
运行
复制
for (Base* b : l) {
    cout << b->getData();
}
票数 1
EN

Stack Overflow用户

发布于 2013-04-03 19:58:41

我将重新定义Base,使其具有一个输出信息的虚拟方法:

代码语言:javascript
运行
复制
class Base {
    friend std::ostream & operator << (std::ostream &os, const Base &b) {
        b.print(os);
        return os;
    }
    virtual void print (std::ostream &os) const = 0;
public:
    virtual ~Base () {}
};

然后,您被迫在每个派生类中实现一个print方法。您的打印循环看起来应该是:

代码语言:javascript
运行
复制
    for (any_list::iterator itr=l.begin();itr!= l.end();++itr)
        std::cout << **itr;

您的列表应该避免管理裸露的指针,因为您将自己置于泄漏内存的风险中。您可以使用智能指针来代替:

代码语言:javascript
运行
复制
typedef std::list< std::unique_ptr<Base> > any_list;

由于unique_ptr需要从指针中显式构造,所以需要更新填充列表的代码。

代码语言:javascript
运行
复制
    l.push_back(std::unique_ptr<Base>(new Derived1));
    l.push_back(std::unique_ptr<Base>(new Derived2));
    l.push_back(std::unique_ptr<Base>(new Derived3));
票数 1
EN

Stack Overflow用户

发布于 2013-04-03 19:38:38

您的cast (Derived1*)*itr等效于一个static_cast,该static_cast声明:

如果类型“指向cv1 B的指针”的prvalue指向实际上是D类型对象的子对象的B,则结果指针指向D类型的包围对象。否则,转换的结果是未定义的。

因此,您有未定义的行为,因为您正在将指向Derived2Derived3对象的指针转换为Derived1*

实现这一目标的正确方法是在std::string s;中定义Base,并为其提供一个接受std::string参数的构造函数。然后,您可以让Derived1的构造函数到Derived3使用适当的字符串参数调用这个构造函数。

如果向其中一个Derived类添加任何额外的成员,您将无法通过多态Base*访问它们。然而,试图这样做是一个糟糕的设计的迹象。您只应该将Base*所指向的对象视为Base对象。也就是说,Base描述了这些对象的接口。

如果确实需要执行特定于指向Base*的对象的派生类的操作,则可以使用dynamic_cast

代码语言:javascript
运行
复制
if (Derived1* p = dynamic_cast<Derived1*>(*itr)) {
  // This condition will only be true if the object pointed to by `*itr` really is a Derived1
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15796341

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档