不同版本的设备的代码结构

Code structure for different versions of devices

本文关键字:代码 结构 版本      更新时间:2023-10-16

我正在编写"设备驱动程序"(C 14(,该版本可以处理用于不同版本的设备的多个版本。该设备驱动程序正在使用基于HTTP的协议通过以太网通过以太网通信的外部PC上运行。所有版本都有共同的功能,但是在协议的某些版本中,某些功能可能会增加。

以下是一个示例:

class ProtocolBase {
public:
    virtual void reset_parameters() {
        std::cout << "reset parameters" << std::endl;
    }
    virtual void set_parameters() {
        std::cout << "set parameters" << std::endl;
    }
};
class ProtocolV1 : public ProtocolBase
{
public:
    void set_parameters() override {
        std::cout << "set parameters for V1" << std::endl;
    }
};
class ProtocolV2 : public ProtocolBase 
{
public:
    void set_parameters() override {
        std::cout << "set parameters for V2" << std::endl;
    }
    void reset_parameters() {
        std::cout << "reset parameters for V2" << std::endl;
    }
    void do_V2() {
        std::cout << "doing V2" << std::endl;
    }
};

以下是main

int main(int argc, char const *argv[])
{
    int version = std::atoi(argv[1]);
    std::unique_ptr<ProtocolBase> protocol = std::make_unique<ProtocolV1>();
    switch (version)
    {
    case 1:
        /* do nothing at the moment */
        break;
    case 2:
        protocol.reset(new ProtocolV2);
        break;
    default:
        break;
    }
    protocol->reset_parameters();
    if(ProtocolV2* p = dynamic_cast<ProtocolV2*>(protocol.get())) { //not sure about this
        p->do_V2();
    }else {
        std::cout << "This functionality is unavailable for this device" << std::endl;
    }
    protocol->set_parameters();
    return 0;
}

我有一种使用dynamic_cast的感觉,不是最好的方法。期待一些反馈。

编辑:根据 @ptaq666的答案,我修改了 ProtocolBaseProtocolV2 as:

class ProtocolBase {
public:
    virtual void do_V(){
        std::cerr << "This functionality is unavailable for this device" << std::endl;
    }
};
class ProtocolV2 : public ProtocolBase 
{
public:
    void do_V() override {
        std::cout << "doing V2" << std::endl;
    }
};

这样,不再需要dynamic_cast,尽管基类必须知道所有功能。这似乎是目前最好的解决方案。

在大多数情况下选择适当的系统体系结构时,答案是"这取决于" :(。最舒适的解决方案是引入特定于协议的行为其构造函数中的ProtocolBase子类

class ProtocolV2 : public ProtocolBase 
{
public:
    ProtocolV2::ProtocolV2(args) {
        // set some params that will determine when do_V2() is called
        // it can be some numeric setting, a callback, or similar
    }
    void set_parameters() override {
        // you can use V2 behavior here maybe?
        std::cout << "set parameters for V2" << std::endl;
    }
    void reset_parameters() override {
        // or here maybe?
        std::cout << "reset parameters for V2" << std::endl;
    }
private:
    void do_V2() {
        std::cout << "doing V2" << std::endl;
    }
};

如果由于某种原因无法执行此操作,则有可能将do_V2()作为公共非虚拟方法,但要在将ProtocolV2作为ProtocolBase的指针传递之前调用它到将使用它的Sysytem。当然,限制是do_V2只能在外面调用您的系统范围,这可能无法真正解决问题。

另一个选择是实际将do_V2()移至接口:

class ProtocolBase {
public:
    virtual void reset_parameters() {
        std::cout << "reset parameters" << std::endl;
    }
    virtual void set_parameters() {
        std::cout << "set parameters" << std::endl;
    }
    virtual void do_V2() {
        std::cout << "not supported" << std::endl;
    }
};

默认情况下将其作为"不支持"行为实现。只有ProtocolV2才能实现此行为作为协议的有效部分。

最后,如果以上都没有,那么您当然可以按照您的建议使用Dynamic_cast。我个人尝试避免dynamic_cast,因为我的办公室伴侣肯定会开始滥用它,但是在某些情况下,这是一个正确的解决方案。

另外,如果您决定施放指针,请使用std::shared_ptr使用dynamic_pointer_cast,而不是从unique_ptr访问RAW指针。

通常,这取决于派生类ProtocolV1ProtocolV2的形成方式,如果各自的成员功能将使用不同的数据成员,则数据成员和天气是什么!p>原因仅仅是因为成员数据没有依赖性,因此成员函数仅对他们已调用的对象的 type

就像具有(非成员(函数超载一样:

void function(ProtocolV1 *){
        std::cout << "set parameters for V1" << std::endl;
}
void function(ProtocolV2 *){
        std::cout << "set parameters for V2" << std::endl;
}

,然后通过类型ProtocolV1 *的指针调用一次,并使用 ProtocolV2 *类型的空指针。

如果您喜欢在问题中介绍的用法的替代方案,甚至可以使用C风格的演员:结果是相同

最后,如果您要调用成员函数以调用它的另一个函数,该函数需要某些数据成员/s,则是/s 不同的,跨派生的类别作为参数/s,那么,除非您引入某种形式的补偿来填写铸件类型中未提供的数据!

祝你好运!