【问题标题】:Subclassing QIODevice by overriding non-virtual methods通过覆盖非虚拟方法继承 QIODevice
【发布时间】:2023-03-27 16:02:01
【问题描述】:

我想从 QIODevice 子类化,因为我正在创建我的自定义设备(自定义串行端口对象)。

我明白了:

writeData(const char *, qint64 ) : qint64
readData(char *, qint64 ) : qint64

在 QIODevice 接口中声明为虚拟,但方法没有:

read(char *, qint64 ) : qint64
write(const char *, qint64 ) : qint64

然后在我的项目中,我有一个这样的串行端口管理器类:

class SerialPortManager{
public:
    SerialPortManager(int type){
         if (type == 1)
             genericSerialPort = new QSerialPort(); //QT framework
         else if (type == 2)
             genericSerialPort = new MySerialPort(); //my custom object, derived from QIODevice
    }

    qint64 write(char * data, qint64 size)
    {
        genericSerialPort->write(data, size);
    }    

private:
    QIODevice* genericSerialPort = 0;
};

而我的自定义串口 (MySerialPort.h) 定义如下:

class MySerialPort : public QIODevice{
    Q_OBJECT
    public:
        explicit MySerialPort(QObject *parent = Q_NULLPTR);
        virtual ~MySerialPort();

        qint64 readData(char *data, qint64 maxSize);
        qint64 writeData(const char *data, qint64 maxSize);

        qint64 write(char * data, qint64 size);

        ...
    };

这里发生的情况是,如果我创建一个类型为 1 的 SerialPortManager 对象(QSerialPort 实例)并在其上调用 write,则会调用 QSerialPort 上的 write 函数。 相反,如果我创建一个类型为 2 的 SerialPortManager 对象(MySerialPort 实例)并在其上调用 write,则不会调用我的 write 函数。

那么,是否可以覆盖QIODevice 的非虚方法write? 否则,如果writeread 不是虚拟的,我该如何创建自定义QIODevice

【问题讨论】:

  • 你不能覆盖非虚拟方法,你只能隐藏它们,这无济于事。您必须覆盖 write_data,而不是写入(您不能这样做)。
  • @n.m.假设我只覆盖 writeData 方法。如果我在我的对象上调用 write 会发生什么?如果基类在其 write 方法上调用我的 writeData 实现,是否会调用它?
  • 它是这样记录的。 doc.qt.io/qt-5/qiodevice.html#details
  • "如果基类在其 write 方法上调用我的 writeData 实现,是否会调用它?"是的,这就是 writeData 是虚拟的。
  • 如果没有 Qt 的调试版本,您将无处可去。拥有它后,使用它来跟踪调用“QIODevice::read”或“write”时发生的情况。那你就明白了。真的。

标签: c++ qt inheritance virtual-functions


【解决方案1】:

这是设计使然。如果 write 和 read 不是虚拟的,则它们不应该被覆盖。

readDatawriteData 是纯虚拟和受保护的。所以我假设writeread 会在内部调用它们。

至于为什么它们不能被覆盖,你必须询问 Qt 设计师。他们很可能会修改一些私有的内部状态等,因此必须将其包装在这些调用中。

Qt 类通常设计得非常好,所以我假设您首先不需要覆盖writeread。如果您这样做,您的设计可能会出现问题。

【讨论】:

  • 好的,但是如果我在我的对象上调用 read 或 write 方法,则不会调用覆盖的 writeData 和 readData。
  • 一般来说,如果我在我的类上调用 read 那么基类的 read 被调用对吗?然后,在它的实现上假设它调用了虚拟的 readData。是叫做 based 还是 derived 的 readData?
  • 您是否打开了设备并处于读/写模式?在您真正开始写/读之前,您可能会遇到错误。检查write/read的返回值,用errorString()检查错误
  • 你的课堂上不应该有read 函数。所以它只有基类功能。 QIODevice 本身没有 readData(它是纯虚拟的),所以你的会被调用。但是根据基本的 OO 原则,派生的将被调用。
  • 如果您不确定什么时候会使用 virtual 调用哪些函数并覆盖它们,我想最好编写一些小程序(没有 qt 只是一些类)并自己尝试一下。这有助于理解其工作原理。
猜你喜欢
  • 2012-06-19
  • 1970-01-01
  • 2016-10-26
  • 2018-07-26
  • 1970-01-01
  • 2016-06-10
  • 2016-01-24
  • 2014-08-21
  • 2016-05-25
相关资源
最近更新 更多