【问题标题】:How to check if object is castable?如何检查对象是否可铸造?
【发布时间】:2021-07-26 10:44:42
【问题描述】:

我有以下课程:

class ATemperatureDevice{};
class AHumidityDevice{};

class BluetoothLeDevice{};

class Sensor1 : BluetoothLeDevice, ATemperatureDevice, AHumidityDevice {};
class Sensor2 : BluetoothLeDevice, AHumidityDevice  {};

我有一个vector<BluetoothLeDevice*>,所有设备都存储在这里。

ATemperatureDevice、AHumidityDevice 和 BluetoothLeDevice 类具有虚函数。

当我选择一个时,我有一个 BluetoothLeDevice。现在我想检查它是否来自 ATemperatureDevice 和/或 AHumidityDevice。

我尝试了 dynamic_cast,当它不可转换时,我应该得到 null,但它说“-fno-rtti 不允许使用'dynamic_cast'”,尽管它们具有虚函数。

检查和投射的最佳方法是什么?

【问题讨论】:

  • 你使用-fno-rtti编译器标志吗?
  • 顺便说一句,vector<BluetoothLeDevice> 不能保存 BluetoothLeDevice 子类的对象,它只能保存 BluetoothLeDevice 类型的对象
  • 普通对象不能有多态性。您的向量将仅存储 BluetoothLeDevice 对象,如果您尝试添加例如,将导致 对象切片 Sensor1 对象。要使多态性起作用,您需要引用或 指针
  • 在解决了上述对象切片问题之后:正确的方法是使用虚函数。无论您认为需要显式转换的原因是什么:这是错误的。这就是虚函数的用途。
  • 顺便说一句,您的设计似乎有点缺陷。我建议您使用包含多个传感器单个设备。每个传感器只能是一种类型(温度、湿度等)。所有传感器都有一个通用的BaseSensor 类,它定义了读取传感器值的接口。然后例如TemperatureSensor 实现了 BaseSensor 接口。然后你的BluetoothLeDevice 有一个指向BaseSensor 的指针向量,用于设备的所有传感器。

标签: c++ oop c++11 arduino esp32


【解决方案1】:

正如人们已经评论的那样,将多态对象 T 存储在 std::vector<T> 中会导致对象切片。您的代码在 C# 中有意义,但在 C++ 中,人们倾向于尽可能使用composition over inheritance 以避免此类问题。在你的情况下,这可能看起来像:https://godbolt.org/z/xna1vjnWh

【讨论】:

    【解决方案2】:

    如果dynamic_cast不被允许,则存储标签以识别派生类。

    //  Test sample
    #include <iostream>
    
    using namespace std;
    class BluetoothLeDevice
    {
    public:
        enum class DerivedClassMetaInfo
        {
            Sensor1Tag,
            Sensor2Tag
        };
    
        virtual ~BluetoothLeDevice()
        {
        }
    
    
    
        virtual DerivedClassMetaInfo tag(void) const = 0;
    
        template <typename TargetType>
        TargetType& to()
        {
            if (TargetType::static_tag != tag())
                throw "Convertion failed";
            return static_cast<TargetType&>(*this);
        }
    };
    
    class Sensor1 : public BluetoothLeDevice
    {
    public:
        static const BluetoothLeDevice::DerivedClassMetaInfo static_tag = BluetoothLeDevice::DerivedClassMetaInfo::Sensor1Tag;
        void show()
        {
            cout << "Sensor1 message" << endl;
        }
        virtual DerivedClassMetaInfo tag(void) const override
        {
            return static_tag;
        }
    };
    
    
    int main()
    {
        BluetoothLeDevice* temp = new Sensor1();
    
        Sensor1& sens = temp->to<Sensor1>();
        sens.show();
        delete temp;
        return 0;
    }
    

    注意:请谨慎使用此代码,因为它不处理棘手的继承树。但是你可以很容易(我猜)改进它

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-01
      • 1970-01-01
      • 2017-01-13
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 2020-12-23
      相关资源
      最近更新 更多