【问题标题】:How to cast an object returned from a function in C++如何转换从 C++ 中的函数返回的对象
【发布时间】:2021-11-17 17:52:56
【问题描述】:

在派生类Derived的虚方法create()中,我返回一个HelpDerived类型的结构。但是,由于我必须将方法的返回类型设置为HelpBase,我发现我需要将返回的对象转换回类型HelpDerived

以下是我的案例。


#include <iostream>


struct HelpBase {
    int a = 0;
    virtual void output() {}
};

struct HelpDerived : HelpBase {
    int b = 0;
    void output() override {}
};


class Base {
public:
    virtual HelpBase create() = 0;
};

class Derived : public Base {
public:
    HelpBase create() override;
};

HelpBase Derived::create() {
    HelpDerived d;
    d.a = 1;
    d.b = 2;
    return d;
}


int main() {
    Derived d;
    auto based = d.create();
    HelpDerived derived = dynamic_cast<HelpDerived &>(based);

    std::cout << derived.a << std::endl;
}

当我运行上面的代码时,我得到了错误

terminate called after throwing an instance of 'std::bad_cast'
  what():  std::bad_cast
Abort trap: 6

我对 C++ 中的对象和强制转换有什么误解?为什么这个方法不起作用?

我能做些什么来解决这个问题?

【问题讨论】:

  • 您有一个 HelpBase 类型的对象,而不是 HelpDerived- 我猜您对在 create 函数中执行的对象切片感到困惑?
  • 多态性应该适用于指针或引用,否则你会受到对象切片的影响。
  • 这能回答你的问题吗? What is object slicing?
  • Derived::create 函数中,当您返回d 时,您将获得slice 对象,只剩下返回的HelpBase 对象。变量based 是一个HelpBase 对象,一旦在create 函数中使用,就无法取回原来的HelpDerived 对象。
  • 谢谢,现在我至少明白是什么导致了我的问题。但我仍然不确定如何解决它。我应该让create 方法返回一个指向HelpBase 对象的指针吗?

标签: c++ inheritance casting


【解决方案1】:

我认为您最好返回一个指针以避免在您的 create 函数中进行对象切片。

#include <iostream>


struct HelpBase {
    int a = 0;
    virtual void output() {}
};

struct HelpDerived : HelpBase {
    int b = 0;
    void output() override {}
};


class Base {
public:
    virtual HelpBase* create() = 0;
};

class Derived : public Base {
public:
    HelpBase* create() override;
};

HelpBase* Derived::create() {
    HelpDerived* d = new HelpDerived;
    d->a = 1;
    d->b = 2;
    return d;
}

int main() {
    Derived d;
    auto based = d.create();
    HelpDerived* derived = dynamic_cast<HelpDerived *>(based);

    std::cout << derived->a << " " << derived->b << std::endl;
    delete derived;
}

【讨论】:

    【解决方案2】:

    我已经用静态转换替换了动态转换,它对我来说几乎没问题。

    #include <iostream>
    
    
    struct HelpBase {
        int a = 0;
        virtual void output() {}
    };
    
    struct HelpDerived : HelpBase {
        int b = 0;
        void output() override {}
    };
    
    
    class Base {
    public:
        virtual HelpBase create() = 0;
    };
    
    class Derived : public Base {
    public:
        HelpBase create() override;
    };
    
    HelpBase Derived::create() {
        HelpDerived d;
        d.a = 3;
        d.b = 2;
        return d;
    }
    
    
    int main() {
        Derived d;
        auto based = d.create();
        HelpDerived derived = static_cast<HelpDerived &>(based);
    
        std::cout << derived.a << std::endl;
        std::cout << derived.b << std::endl;
    }
    

    输出:

    3

    32726

    请注意,a 值是正确的,而 b 是垃圾。这是因为未调用 derived 构造函数。 一般来说,不建议从基类强制转换为派生类,因为派生类可能比基类拥有更多的数据成员。 推荐阅读:https://www.bogotobogo.com/cplusplus/upcasting_downcasting.php

    【讨论】:

    • 绝对调用派生构造函数,问题是对象切片。你的回答并没有真正解决问题。
    猜你喜欢
    • 2021-01-30
    • 2021-08-09
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 2021-07-20
    • 1970-01-01
    • 2015-07-09
    • 2015-12-15
    相关资源
    最近更新 更多