【问题标题】:Casting vector of base class to derived class将基类的向量转换为派生类
【发布时间】:2020-08-30 02:57:09
【问题描述】:

我有一个名为 Goods 的抽象类。 基于这个类,我派生出其他类,例如 PotatoesToysWine

Beer 
    b1(/*price*/ 4, 
       /*quantity*/ 1000, 
       /*type*/ "red", 
       /*name*/ "Skolls"),

    b2(/*price*/ 3.5, 
       /*quantity*/ 1000, 
       /*type*/ "blonde", 
       /*name*/ "Braun");

Potatoes
    p1(/*price*/ 2,
        /*quantity*/ 1000,
        /*type*/ "red"),

    p2(/*price*/ 2,
        /*quantity*/ 1000,
        /*type*/ "white");

Wine
    w1(/*price*/ 4.5,
        /*quantity*/ 1000,
        /*name*/ "Chavignon",
        /*origin*/ "France",
        /*year*/ 2000),

Market market;

market.Consumer.push_back(&b1);
market.Consumer.push_back(&b2);
market.Consumer.push_back(&p1);
market.Consumer.push_back(&p2);
market.Consumer.push_back(&w1);

我将它们添加到一个名为 Consumer 的向量中,声明如下:

std::vector<Goods*> Consumer

我想不通的是如何在这样的 for 语句中将每个元素从 Consumer 转换为其 Derived 等效项,以便我可以基于派生类应用一些特定方法.

for (int i = 0; i < Consumer.size(); i++) {
     Wine* Consumer[i] = static_cast<Goods*>(Consumer[i]);

当我尝试按上述方式进行操作时,我收到关于 i 值的错误:“表达式必须具有常量值”

商品.H

#pragma once
#include <iostream>
#include <string>
#include <vector>

//Base class
class Goods
{
protected:
    double Price;
    double Quantity;

public:
    virtual void setprice(double prc) = 0;
    virtual double getprice() const = 0;

    virtual void setquantity(double qty) = 0;
    virtual double getquantity() const = 0;

    virtual std::string getID() const = 0;

    virtual void print() = 0;

    Goods();
    Goods(double prc, double qty);
    ~Goods();
};

【问题讨论】:

  • 使用多态来实现你的目标。
  • @ElvisOric,我已经有虚拟(纯)函数,(在我的示例中)是每个派生类的 getter 和 setter。您的意思是添加其他我稍后将在派生类中覆盖的虚函数?
  • 好吧,你想做什么,在你的派生类中重写那个操作。
  • 回复:“我已经有虚拟 ... 函数”——不在您显示的代码中。没有人能从代码片段中给你有用的答案。
  • @PeteBecker 这是一段很长的代码,有很多标题和其他技术细节。我试图尽可能简洁明了。

标签: c++ oop casting polymorphism


【解决方案1】:

我认为实现这一点的最佳方法是使用继承和运行时多态性。你有你的基类Goods,它声明了一个接口(虽然是纯虚方法),然后由你的派生类实现(例如Wine)。

这意味着您无需进行任何转换即可使用您的自定义行为,您甚至不需要知道您的指针实际指向的 type 是什么,只需它继承自 @987654323 @ 并且必须实现它的接口。

这使您可以编写如下代码:

for (int i = 0; i < Consumer.size(); i++) {
     Goods* consumer = Consumer[i];
     consumer->/* some pure virtual method in Goods, will call the overridden method in whatever object consumer points too */

这确实有一个限制,您不能调用未在Goods 中声明的方法。然而,这比在不知道任何真正类型是什么的情况下尝试执行强制转换要安全得多。

如果您真的想将所有对象转换为不同的类型,您可以使用static_castdynamic_cast 来实现,两者都不是很漂亮,但如果您可以保证通过一些逻辑,实际上你也试图转换它的类型,使用static_cast,如果不使用dynamic_cast(不正确的转换static_cast是UB,dynamic_cast将返回nullptr

要做到这一点,你可以这样做:

for (int i = 0; i < Consumer.size(); i++) {
     auto* consumer = dynamic_cast<Wine*>(Consumer[i]);
     some_other_vector.emplace_back(consumer); // Assuming your other vector starts empty

我这里用过dynamic_cast,真的你也应该检查consumer是否也有效。使用static_cast 将绕过dynamic_cast 的运行时开销,但几乎在转换为派生类型时应该永远不要使用它。

【讨论】:

  • 那么,有没有办法通过铸造来做到这一点?只能通过其他纯虚方法?
  • 如果您想访问未在您访问它们的类型中定义的方法(在这种情况下为Goods),那么不,您不能。但是,根据您的示例,您似乎不需要这样做和/或您可以轻松更改代码以利用运行时多态性
  • @FusiFlag 抱歉刚刚意识到你的意思:p,我已经更新了我的答案,通过投射来做到这一点
  • “some_other_vector”应该是什么?什么样的载体?因为如果它是 Consumer 的副本,那么情况与以前相同。仍然无法访问派生的特定方法
  • 我需要为每种类型的派生对象初始化一个吗?例如std::vector&lt;Wine*&gt; cpy_wstd::vector&lt;Toys*&gt; cpy_t 等等?
猜你喜欢
  • 2017-01-08
  • 2013-11-17
  • 1970-01-01
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多