从抽象类向下转换到右侧模板的最佳方式

Best way to downcast to right template from abstract class

本文关键字:最佳 方式 抽象类 转换      更新时间:2023-10-16

我最近有一个C++赋值,在那里我遇到了一个关于多态性的问题。

我们需要将值存储在模板化的类中,该类继承自抽象接口类。

enum eOperandType {
    Int8,
    Int16,
    Int32,
    Float,
    Double
};
class IOperand {
public:
    virtual eOperandType getType() const = 0; // Type of the instance
    virtual IOperand const *operator+(IOperand const &rhs) const = 0;
    virtual ~IOperand() {}
};
template<typename T>
class Operand : public IOperand {
public:
    Operand(T const &n, eOperandType type);    
    eOperandType getType() const;    
    IOperand const *operator+(IOperand const &rhs) const;
    T const value;
    eOperandType const type;
};

对于所有的作业,我们被禁止编辑IOperand类,但可以自由使用后面需要的任何类。

在代码执行的后期,数字被实例化,然后作为IOperand*存储在容器中。然后我们得到这个列表来操纵数字。

我的问题是找到如何将IOperand*向下转换为正确的操作数类型,以便对其进行操作并获得其值。

我尝试了一周的多种方法,研究了所有模板的行为(当我尝试使用Operand<op.getType()>,T是枚举时遇到了麻烦)

我的实际设计使用了很多交换机:

switch (op.value->getType()) {
    case Int8:
        if (dynamic_cast<Operand<int8_t>*>(op.value.get())->value != dynamic_cast<Operand<int8_t>*>(stack.front().get())->value) {
            throw RuntimeError("Assert failed. Whoopsie");
        }
        break;
    case Int16:
        if (dynamic_cast<Operand<int16_t>*>(op.value.get())->value != dynamic_cast<Operand<int16_t>*>(stack.front().get())->value) {
            throw RuntimeError("Assert failed. Whoopsie");
        }
        break;
    case Int32:
        if (dynamic_cast<Operand<int32_t>*>(op.value.get())->value != dynamic_cast<Operand<int32_t>*>(stack.front().get())->value) {
            throw RuntimeError("Assert failed. Whoopsie");
        }
        break;
    case Float:
        if (dynamic_cast<Operand<float>*>(op.value.get())->value != dynamic_cast<Operand<float>*>(stack.front().get())->value) {
            throw RuntimeError("Assert failed. Whoopsie");
        }
        break;
    case Double:
        if (dynamic_cast<Operand<double>*>(op.value.get())->value != dynamic_cast<Operand<double>*>(stack.front().get())->value) {
            throw RuntimeError("Assert failed. Whoopsie");
        }
        break;
    default:
        throw RuntimeError("wut");
        break;
}

解决我的问题最好的清洁解决方案是什么?我需要在多个位置和函数上"向下转换"我的值,以便操作该值,这里的断言代码只是其他代码中的一个例子。

我可以在这里使用C++14,但不能使用任何外部库。

当我试着用T的Operand时撞墙了枚举

模板在编译时进行评估。编译器为您使用的每种类型生成代码。像op.getType()这样的动态值需要编译器在编译之后创建代码,这在JIT编译的语言中当然是可能的,但在C++中则不然。

恐怕你的问题没有"漂亮"的解决办法。正如您所展示的,您确实需要一种switch语句,并根据getType()的值来决定您的演员阵容。根据您的使用情况,虚拟函数可以帮助您,例如,如果您想知道T 的字节大小

virtual size_t getSizeOf()
{
    return sizeof(T);
}

但由于不允许修改IOperand,因此您只能使用您的解决方案。