成员对象中枚举的行为
C++ - Behavior of enums in member object
我在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.
您没有为MemberClass
定义默认构造函数,编译器提供的隐式构造函数用于在ParentClass
中初始化objectMember
。隐式构造函数不会为您初始化mError
,因此您得到的是随机值。
为MemberClass
添加显式默认构造函数:
MemberClass::MemberClass() :
QObject(NULL), mError(NoError)
{
}
或ParentClass
的成员初始化:
ParentClass::ParentClass(QObject *parent) :
QObject(parent), objectMember(NULL)
{
pointerMember = new MemberClass(this);
}
在这里声明成员
private:
MemberClass objectMember;
没有为构造函数提供参数。它正在调用QObject的默认构造函数(它不在您的代码中),并且没有初始化枚举。
我只是复制并粘贴您的代码到一个干净的项目。当使用MSVC2010用Qt 4.8.0编译时,一切对我来说都很正常。您重新构建项目并重新运行qmake了吗?
我克隆了你的代码,运行它,没有问题。
我建议您清理项目并重新构建它。代码看起来也不错。我认为编译器缓存在代码修改期间被损坏(有时会发生),并且生成了错误的代码,清洁项目应该修复它。
实际上您并没有得到一个自动生成的构造函数。这样做的原因是,您只会在根本没有定义构造函数的类中获得这样的构造函数。您为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;
}
你可以在这里看到结果
如果您在堆栈上定义对象,如:
MemberOfMyClass member;
当您超出作用域时,您的对象信息丢失
MemberClass单参数构造函数有<<"mError初始化。";这在输出中是没有的。编译器生成的默认构造函数不知道成员变量的期望值,所以如果为这些变量分配的内存有垃圾,这些垃圾就会泄露。
你从来没有在你的ParentClass的构造函数中初始化"objectMember"值,但是你初始化了"pointerMember"。我敢打赌,"objectMember"也是在测试中给您带来问题的值,这不是巧合。我没有QT,但是如果你添加
会发生什么?objectmember = *pointerMember;
初始化后的构造函数我已经有一段时间没有使用c++了,所以我可能错过了一些明显的东西,但我敢打赌这是你的问题。
还请注意,上次我使用它时,Visual Studio的调试器倾向于为程序员设置所有未初始化的值为0。一旦代码被实际编译,这种情况就不会发生(尽管我相信有些编译器可能会这样做,比如GCC),所以这可能就是您看到此错误而其他编译器没有看到此错误的原因。因此,它可能有助于使您正在查找的值为"IsError" -这样,您将查找的值将为1,而不是默认的未初始化值。- 枚举成员与静态 int 成员?
- C++ 使用枚举类对象分配 std::map 值
- 从类访问枚举成员
- 枚举成员不是类型错误
- std::映射键作为模板化结构与枚举成员
- 设置类的枚举成员无效地使用"枚举"
- 如何访问结构和枚举成员形成一类
- 是否可以在 constexpr 函数中遍历枚举成员,因此值为 constexpr
- 获取 [枚举成员?] 的封闭类型
- 如何使用 SWIG 枚举枚举成员
- 通过int值访问枚举成员
- '='应初始化所有枚举成员或仅初始化第一个枚举成员;
- 为什么可以获取此枚举成员值,而不必先深入研究嵌套枚举
- 将具有枚举成员的非托管结构封送到 C#
- 为类模板的枚举成员定义 std::hash
- 缩短C++枚举成员的路径(使用 typedef 或 typename),以用作模板参数
- gtest枚举和对象之间的比较
- C++类枚举成员变量
- 检查是否已定义枚举成员
- 跟踪专用模板对象的枚举成员值