Qt继承和类构造函数混淆
Qt inheritance and classes constructors confusion
我对 Qt C++ 有点陌生,我觉得我遗漏了一个小东西,但不知道是什么。
我正在尝试制作一个简单的 Qt C++ 应用程序以熟悉它,但我遇到了一些问题,首先,我有 votor class,它是主要应用程序 class , 还有一个叫做 recorder 的 class , 将在 main votor class 中使用。为了简单起见,我省略了不相关的部分,
以下是文件:
votor.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_votor.h"
#ifndef TSTRECORD_H
#define TSTRECORD_H
#endif
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
#include "recorder.h"
class VOTor : public QMainWindow
{
Q_OBJECT
public:
VOTor(QWidget *parent = Q_NULLPTR);
recorder xs;
private:
Ui::VOTorClass ui;
};
votor.cpp
#include "votor.h"
VOTor::VOTor(QWidget *parent) : QMainWindow(parent), xs(parent)
{
ui.setupUi(this);
//xs = recorder();
}
recorder.h
#pragma once
#include <QDebug>
#include <QObject>
#include <QtCore/qbuffer.h>
#include <QtCore/qiodevice.h>
#include<QtMultimedia/qaudioformat.h>
#include<QtMultimedia/qaudiodeviceinfo.h>
#include<QtMultimedia/qaudioinput.h>
class recorder : public QObject
{
Q_OBJECT
public:
// recorder();
recorder(QObject *parent);
~recorder();
//Some functions related to recording omitted for more focus
private:
//omitted members for simplicity, just some integers, chars and qt objects not related to problem
recorder.cpp
#include "recorder.h"
recorder::recorder(QObject *parent) : QObject(parent)
{
//just initializing the omitted members normally
}
//recorder::recorder() {}
recorder::~recorder()
{
}
如你所见,recorder 对象是 votor class 内部的一个成员。现在,我需要调用记录器构造函数来初始化它的父项。现在,我知道我不能只做 (inside votor.h)
recorder xs(parent);
所以,
1-除了初始化列表之外,有没有办法调用记录器构造函数?
我想要另一种方式,因为使用 recorder xs(..) 比初始化列表更方便,我觉得(只是觉得)使用初始化列表很重(不是性能方面的,而是可读性方面的)。我也知道我可以使用动态分配,但我不想在没有充分理由的情况下使用它。
2- 我决定使用初始化列表来调用记录器构造函数并将 (Qobject* parent) 传递给记录器。代码构建成功,但是当 运行 时,它给出了访问冲突错误,我不明白为什么......
它给:
"Access violation reading location 0x7C32F08D."
我想我遗漏了一些小东西..我希望知道哪里出了问题。
编辑:
正如@p-a-o-l-o 所建议的那样,访问冲突来自省略的代码,因此,我将其发布在这里,因为我不知道我的代码中存在什么问题:
完整版recoder.h
class recorder : public QObject
{
Q_OBJECT
public:
recorder();
//recorder(QObject *parent);
~recorder();
void record();
void stop();
public slots:
void stateChanged(QAudio::State);
private:
unsigned char state;
QBuffer* voiceBuffer;
QAudioFormat* format;
QAudioDeviceInfo* info;
QAudioInput* audioIn;
unsigned char writeWav(QByteArray*);
};
根据调试模式,部分导致访问冲突,这是记录器的构造函数class
recorder::recorder() : QObject(Q_NULLPTR)
{
state = 0;
voiceBuffer->open(QIODevice::WriteOnly);
format->setSampleRate(8000);
format->setChannelCount(1);
format->setSampleRate(16);
format->setByteOrder(QAudioFormat::LittleEndian);
format->setCodec("audio/pcm");
format->setSampleType(QAudioFormat::SignedInt);
*info = QAudioDeviceInfo::defaultInputDevice();
audioIn = &QAudioInput(*info, *format);
//audioIn->stateChanged.connect(stateChanged);
//connect(audioIn, &QAudioInput::stateChanged, stateChanged);
connect(audioIn, SIGNAL(stateChanged (QAudio::State) ), this, SLOT(stateChanged(QAudio::State)));
}
关于问题 #1:正如评论中正确建议的那样,QObject
派生的 class 的正确构造函数将具有 nullptr
默认参数:
recorder(QObject *parent = Q_NULLPTR);
如果您真的需要 parent
object 来初始化构造中的其他成员,您别无选择,必须以某种方式调用该构造函数。
否则,有一个 no-arguments 构造函数并在那里初始化其他成员:
recorder::recorder() : QObject(Q_NULLPTR)
{
//just initializing the omitted members normally
}
这样的构造函数会自动调用,这里不需要初始化列表。
如果 recorder
object 仍然需要 parent,请在 VOTor
构造函数中给它一个:
VOTor::VOTor(QWidget *parent) : QMainWindow(parent)
{
ui.setupUi(this);
xs.setParent(parent);
}
关于问题 #2:据我从您发布的代码中可以看出,访问冲突与 Qt parenting 无关,必须是与 recorder
构造函数中的(省略的)代码相关。
只是为了清除它:parent成员object总是安全的,因为它会在之前~QObject()
被调用,因此它将从 children 列表中删除 ,然后 ~QObject()
可能会对其调用 delete。
以OP代码为例,析构函数顺序如下:
~VOTor()
~recorder() ---> xs is removed from the children list
.
.
.
~QObject() ---> will call delete on all children, but ws is not in the list anymore
Qt documentation对于parents和children的construction/destruction的顺序已经很清楚了:简而言之,如果child创建于堆栈一切都会好起来,直到 child 在 在 parent 之后创建。
但是,同样,如果 child 恰好是 parent class 的成员,由于上述原因,它也没有问题(即使它的构造实际上发生了 在它的parent之前)。
我对 Qt C++ 有点陌生,我觉得我遗漏了一个小东西,但不知道是什么。
我正在尝试制作一个简单的 Qt C++ 应用程序以熟悉它,但我遇到了一些问题,首先,我有 votor class,它是主要应用程序 class , 还有一个叫做 recorder 的 class , 将在 main votor class 中使用。为了简单起见,我省略了不相关的部分, 以下是文件:
votor.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_votor.h"
#ifndef TSTRECORD_H
#define TSTRECORD_H
#endif
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
#include "recorder.h"
class VOTor : public QMainWindow
{
Q_OBJECT
public:
VOTor(QWidget *parent = Q_NULLPTR);
recorder xs;
private:
Ui::VOTorClass ui;
};
votor.cpp
#include "votor.h"
VOTor::VOTor(QWidget *parent) : QMainWindow(parent), xs(parent)
{
ui.setupUi(this);
//xs = recorder();
}
recorder.h
#pragma once
#include <QDebug>
#include <QObject>
#include <QtCore/qbuffer.h>
#include <QtCore/qiodevice.h>
#include<QtMultimedia/qaudioformat.h>
#include<QtMultimedia/qaudiodeviceinfo.h>
#include<QtMultimedia/qaudioinput.h>
class recorder : public QObject
{
Q_OBJECT
public:
// recorder();
recorder(QObject *parent);
~recorder();
//Some functions related to recording omitted for more focus
private:
//omitted members for simplicity, just some integers, chars and qt objects not related to problem
recorder.cpp
#include "recorder.h"
recorder::recorder(QObject *parent) : QObject(parent)
{
//just initializing the omitted members normally
}
//recorder::recorder() {}
recorder::~recorder()
{
}
如你所见,recorder 对象是 votor class 内部的一个成员。现在,我需要调用记录器构造函数来初始化它的父项。现在,我知道我不能只做 (inside votor.h)
recorder xs(parent);
所以, 1-除了初始化列表之外,有没有办法调用记录器构造函数? 我想要另一种方式,因为使用 recorder xs(..) 比初始化列表更方便,我觉得(只是觉得)使用初始化列表很重(不是性能方面的,而是可读性方面的)。我也知道我可以使用动态分配,但我不想在没有充分理由的情况下使用它。
2- 我决定使用初始化列表来调用记录器构造函数并将 (Qobject* parent) 传递给记录器。代码构建成功,但是当 运行 时,它给出了访问冲突错误,我不明白为什么...... 它给: "Access violation reading location 0x7C32F08D."
我想我遗漏了一些小东西..我希望知道哪里出了问题。
编辑: 正如@p-a-o-l-o 所建议的那样,访问冲突来自省略的代码,因此,我将其发布在这里,因为我不知道我的代码中存在什么问题:
完整版recoder.h
class recorder : public QObject
{
Q_OBJECT
public:
recorder();
//recorder(QObject *parent);
~recorder();
void record();
void stop();
public slots:
void stateChanged(QAudio::State);
private:
unsigned char state;
QBuffer* voiceBuffer;
QAudioFormat* format;
QAudioDeviceInfo* info;
QAudioInput* audioIn;
unsigned char writeWav(QByteArray*);
};
根据调试模式,部分导致访问冲突,这是记录器的构造函数class
recorder::recorder() : QObject(Q_NULLPTR)
{
state = 0;
voiceBuffer->open(QIODevice::WriteOnly);
format->setSampleRate(8000);
format->setChannelCount(1);
format->setSampleRate(16);
format->setByteOrder(QAudioFormat::LittleEndian);
format->setCodec("audio/pcm");
format->setSampleType(QAudioFormat::SignedInt);
*info = QAudioDeviceInfo::defaultInputDevice();
audioIn = &QAudioInput(*info, *format);
//audioIn->stateChanged.connect(stateChanged);
//connect(audioIn, &QAudioInput::stateChanged, stateChanged);
connect(audioIn, SIGNAL(stateChanged (QAudio::State) ), this, SLOT(stateChanged(QAudio::State)));
}
关于问题 #1:正如评论中正确建议的那样,QObject
派生的 class 的正确构造函数将具有 nullptr
默认参数:
recorder(QObject *parent = Q_NULLPTR);
如果您真的需要 parent
object 来初始化构造中的其他成员,您别无选择,必须以某种方式调用该构造函数。
否则,有一个 no-arguments 构造函数并在那里初始化其他成员:
recorder::recorder() : QObject(Q_NULLPTR)
{
//just initializing the omitted members normally
}
这样的构造函数会自动调用,这里不需要初始化列表。
如果 recorder
object 仍然需要 parent,请在 VOTor
构造函数中给它一个:
VOTor::VOTor(QWidget *parent) : QMainWindow(parent)
{
ui.setupUi(this);
xs.setParent(parent);
}
关于问题 #2:据我从您发布的代码中可以看出,访问冲突与 Qt parenting 无关,必须是与 recorder
构造函数中的(省略的)代码相关。
只是为了清除它:parent成员object总是安全的,因为它会在之前~QObject()
被调用,因此它将从 children 列表中删除 ,然后 ~QObject()
可能会对其调用 delete。
以OP代码为例,析构函数顺序如下:
~VOTor()
~recorder() ---> xs is removed from the children list
.
.
.
~QObject() ---> will call delete on all children, but ws is not in the list anymore
Qt documentation对于parents和children的construction/destruction的顺序已经很清楚了:简而言之,如果child创建于堆栈一切都会好起来,直到 child 在 在 parent 之后创建。 但是,同样,如果 child 恰好是 parent class 的成员,由于上述原因,它也没有问题(即使它的构造实际上发生了 在它的parent之前)。