Jay
Jay

Reputation: 2902

C++ - Behavior of enums in member object

I am using Qt in C++ and am struggling with an enum. Consider a case like the one below:

Clone on 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

Working with the variable mError of type ErrorType doesn't work as expected (it takes on strange and inconsistent values during execution).

I get output like this:

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.

Upvotes: 2

Views: 821

Answers (8)

DuncanACoulter
DuncanACoulter

Reputation: 2146

You are not in fact getting an automatically generated constructor. The reason for this is that you will only be given such a constructor in a class which does not define a constructor at all. You define a constructor for MemberClass(QObject *parent = 0) but because it exists you are not assigned an automatically generated noargs constructor.

A similar but related example might illustrate the class of problem:

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;
}

You can see the result here

Upvotes: 1

Marshall Conover
Marshall Conover

Reputation: 845

You never initialize the "objectMember" value in your ParentClass' constructor, but you do initialize the "pointerMember". I'd bet it's not coincidence that "objectMember" is also the value giving you issues in your test. I don't have QT, but what happens if you add

objectmember = *pointerMember;

to the constructor after you initialize the pointerMember? It's been a bit since I've played with C++, so I may be missing something obvious, but I'd bet this is your issue.

Also note that, last I played with it, Visual Studio's debugger tends to set all non-initialized values to 0 for the programmer. This does not happen once the code has actually been compiled (though I believe some compilers may do it, such as GCC), so it's possible that's why you're seeing this error and others are not. Because of this, it might help to make the value you're looking for be "IsError" - that way, the value you'll be looking for will be 1, and not the default uninitialized value.

Upvotes: 0

Marek R
Marek R

Reputation: 38062

I cloned your code run it and there was no problems.
I recommend you to clean your project and build it again. Code looks also looks OK. I think compiler cache get corrupted during code modification (sometimes it happens) and wrong code was generated, clean project should fix it.

Upvotes: 1

Phlucious
Phlucious

Reputation: 3843

I just copied and pasted your code into a clean project. When compiled with Qt 4.8.0 using MSVC2010, everything appeared normal to me. Have you rebuilt your project and re-run qmake?

Upvotes: 1

Chawathe Vipul S
Chawathe Vipul S

Reputation: 1696

The MemberClass single argument constructor has line << "mError initialized."; that's absent in the output. Compiler generated default constructor is clueless of desired values for member variables, so if the memory allocated for these has garbage, this garbage is leaked..

Upvotes: 0

Jay
Jay

Reputation: 14471

In your declaration of a member here

private:
    MemberClass objectMember;

You're not providing a parameter for the constructor. It's calling the default constructor for QObject (which is not in your code) and which does not initialize the enum.

Upvotes: 1

Stephen Chu
Stephen Chu

Reputation: 12832

You didn't define a default constructor for MemberClass and a compiler supplied implicit one is used to initialize objectMember in ParentClass. The implicit constructor does not initialize mError for you, thus the random value you get.

Either add a explicit default constructor to MemberClass:

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

or a member initialization to ParentClass:

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

Upvotes: 10

fatihk
fatihk

Reputation: 7919

if you define your object on the stack like :

MemberOfMyClass member;

when you go out of scope, your object information is lost

Upvotes: 0

Related Questions