【问题标题】:C++ - Behavior of enums in member objectC++ - 成员对象中枚举的行为
【发布时间】:2013-03-28 05:21:02
【问题描述】:

我在 C++ 中使用 Qt 并且正在努力解决枚举问题。考虑如下情况:

在 GitHub 上克隆:https://github.com/jif/enum

// memberclass.h =======================================================
#ifndef MEMBERCLASS_H
#define MEMBERCLASS_H

#include <QObject>

class MemberClass : public QObject
{
    Q_OBJECT
public:
    enum ErrorType {
        NoError,
        IsError
    };
    explicit MemberClass(QObject *parent = 0);
    void setError(ErrorType errorType);
    MemberClass::ErrorType error() const;
    void otherMethod();
private:
    MemberClass::ErrorType mError;
};

#endif // MEMBERCLASS_H

// memberclass.cpp =======================================================
#include "memberclass.h"
#include <QDebug>

MemberClass::MemberClass(QObject *parent) :
    QObject(parent)
{
    mError = NoError;
    qDebug() << "mError initialized.";
}
MemberClass::ErrorType MemberClass::error() const {
    return mError;
}
void MemberClass::setError(ErrorType errorType) {
    mError = errorType;
}
void MemberClass::otherMethod() {
    qDebug() << "    In otherMethod()...";
    qDebug() << "      mError = " << mError;
    qDebug() << "      NoError = " << NoError;
    qDebug() << "      IsError = " << IsError;
    qDebug() << "    End otherMethod()";
}

// parentclass.h =======================================================
#ifndef PARENTCLASS_H
#define PARENTCLASS_H

#include <QObject>
#include "memberclass.h"

class ParentClass : public QObject
{
    Q_OBJECT
public:
    explicit ParentClass(QObject *parent = 0);
    void testEnumStuff();
private:
    MemberClass objectMember;
    MemberClass *pointerMember;
};

#endif // PARENTCLASS_H

// parentclass.cpp =======================================================
#include "parentclass.h"
#include <QDebug>

ParentClass::ParentClass(QObject *parent) :
    QObject(parent)
{
    pointerMember = new MemberClass(this);
}
void ParentClass::testEnumStuff() {
    qDebug() << "Just initialized...";
    qDebug() << "  pointerMember::mError = " << pointerMember->error();
    qDebug() << "  objectMember::mError =  " << objectMember.error();
    qDebug() << "Calling otherMethod() on each member...";
    qDebug() << "  In pointerMember...";
    pointerMember->otherMethod();
    qDebug() << "  In objectMember...";
    objectMember.otherMethod();
    qDebug() << "  pointerMember::mError = " << pointerMember->error();
    qDebug() << "  objectMember::mError =  " << objectMember.error();
    qDebug() << "Done.";
}

// main.cpp =======================================================
#include <QCoreApplication>
#include "parentclass.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ParentClass parent;
    parent.testEnumStuff();
    return a.exec();
}


// enum.pro =======================================================
QT       += core

QT       -= gui

TARGET = enum
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE = app


SOURCES += main.cpp \
    parentclass.cpp \
    memberclass.cpp

HEADERS += \
    parentclass.h \
    memberclass.h

使用 ErrorType 类型的变量 mError 无法按预期工作(它在执行期间采用奇怪且不一致的值)。

我得到这样的输出:

mError initialized.
mError initialized.    
Just initialized... 
  pointerMember::mError =  0 
  objectMember::mError =   0 
Calling otherMethod() on each member... 
  In pointerMember... 
    In otherMethod()... 
      mError =  0 
      NoError =  0 
      IsError =  1 
    End otherMethod() 
  In objectMember... 
    In otherMethod()... 
      mError =  13498688 
      NoError =  0 
      IsError =  1 
    End otherMethod() 
  pointerMember::mError =  0 
  objectMember::mError =   13498688 
Done.

【问题讨论】:

  • 发布一个完整的例子
  • mError 在哪里初始化?
  • 确实看起来像初始化错误。您应该在 MemberOfMyClass 构造函数中编写如下内容:mError = NoError;
  • 发布的代码在 Qt 5.4.3 中使用 Visual Studio 2005 编译器可以正常工作(打印零和一的预期输出)...您使用的是哪个编译器/qt,是否有可能某些配置是错了吗?
  • 我在Qt5.0.1,clang,OS-X10.8.3

标签: c++ qt class pointers member


【解决方案1】:

您没有为MemberClass 定义默认构造函数,编译器提供的隐式构造函数用于在ParentClass 中初始化objectMember。隐式构造函数不会为你初始化mError,因此你得到的是随机值。

要么给MemberClass添加一个显式的默认构造函数:

MemberClass::MemberClass() :
    QObject(NULL), mError(NoError)
{
}

或成员初始化为ParentClass:

ParentClass::ParentClass(QObject *parent) :
    QObject(parent), objectMember(NULL)
{
    pointerMember = new MemberClass(this);
}

【讨论】:

  • 我在 MemberClass (qDebug() &lt;&lt; "mError initialized.";) 的构造函数中添加了一个调试打印,它为 objectMemberpointerMember 打印,告诉我在这两种情况下都使用了我的显式构造函数,mError已正确初始化...
  • 这与可用的可能性不符。我想说的部分问题还在于您正在使用带有默认参数的显式,这对我来说根本没有意义。除此之外,您编写代码的方式可以解释对我的调用,因为您没有编写默认或复制构造函数,而是提供了自己的单独构造函数。尝试初始化 pointerMember(new MemberClass(this)) 而不是在正文中,如果您的 inits 计数停止打印两次,我不会感到惊讶。那并在您的调试中打印出“父”的地址是什么。您的代码也有明显的内存泄漏。
【解决方案2】:

在你的成员声明中

private:
    MemberClass objectMember;

您没有为构造函数提供参数。 它正在调用 QObject 的默认构造函数(不在您的代码中)并且不会初始化枚举。

【讨论】:

    【解决方案3】:

    我刚刚将您的代码复制并粘贴到一个干净的项目中。当使用 MSVC2010 使用 Qt 4.8.0 编译时,对我来说一切正常。你重建你的项目并重新运行 qmake 了吗?

    【讨论】:

      【解决方案4】:

      我克隆了你的代码运行它,没有问题。
      我建议你清理你的项目并重新构建它。 代码看起来也不错。我认为编译器缓存在代码修改期间被损坏(有时会发生)并且生成了错误的代码,干净的项目应该修复它。

      【讨论】:

        【解决方案5】:

        您实际上并没有获得自动生成的构造函数。这样做的原因是你只会在一个根本没有定义构造函数的类中获得这样的构造函数。您为 MemberClass(QObject *parent = 0) 定义了一个构造函数,但是因为它存在,所以没有为您分配一个自动生成的 noargs 构造函数。

        一个类似但相关的例子可以说明问题的类别:

        class Base
        {
            /*Has a constructor therefore does not get a free 
             noargs constructor*/
            Base(int i) {}; 
        };
        
        class Derived : public Base
        {
        };
        
        int main()
        {
             /*Not actually possible because Derived will get a free noargs constructor
               which will attempt to invoke the non existant no args constructor of Base.
             */
             Derived d; 
        
             return 0;
        }
        

        你可以看到结果here

        【讨论】:

        • MemberClass 的构造函数初始化mError。请参阅原始帖子。
        • 除非在调用无参数构造函数(你没有)的情况下,例如成员类对象成员; //你需要一个没有参数的构造函数
        【解决方案6】:

        如果您在堆栈上定义对象,例如:

        MemberOfMyClass member;
        

        当您超出范围时,您的对象信息会丢失

        【讨论】:

          【解决方案7】:

          MemberClass 单参数构造函数有行

          【讨论】:

          • pointerMember = new MemberClass(this);在构造函数执行完成之前传递 this。类型转换还成功吗?
          • 抱歉,我更新了帖子中的代码,但没有更新输出:(这些行确实出现在输出中。
          【解决方案8】:

          您永远不会在 ParentClass 的构造函数中初始化“objectMember”值,但您确实初始化了“pointerMember”。我敢打赌,“objectMember”也是在测试中给您带来问题的价值,这不是巧合。我没有QT,但是如果你添加会发生什么

          objectmember = *pointerMember;
          

          初始化pointerMember 后到构造函数?自从我玩过 C++ 以来已经有一段时间了,所以我可能遗漏了一些明显的东西,但我敢打赌这是你的问题。

          另外请注意,上次我使用它时,Visual Studio 的调试器倾向于为程序员将所有未初始化的值设置为 0。一旦实际编译了代码,就不会发生这种情况(尽管我相信某些编译器可能会这样做,例如 GCC),因此这可能就是您看到此错误而其他人没有看到的原因。因此,将您要查找的值设为“IsError”可能会有所帮助 - 这样,您要查找的值将是 1,而不是默认的未初始化值。

          【讨论】:

            猜你喜欢
            • 2011-05-08
            • 2020-03-19
            • 1970-01-01
            • 1970-01-01
            • 2019-04-10
            • 2016-03-04
            • 1970-01-01
            • 2018-11-05
            • 1970-01-01
            相关资源
            最近更新 更多