Pergunta

I have a class B derived from A where there's a member called type which I want to access from a method from class B but instead of actual value I get a 0 but if I cast this to A inside B method it will work fine, like this: ((A*)this)->type so it's give me the actual value instead of 0. Can someone explain that? I wrote a short version of my actual class to give an code example.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

enum TYPE
{
    T_INTEGER = 2,
  T_FLOAT = 4
};

struct A
{
  enum TYPE type;
  A(enum TYPE);
  A();
  int print();
};

struct B : A
{
  enum TYPE type;
  B(enum TYPE);
};

struct Number : B
{
  union
  {
        int intvalue;
        float floatvalue;
  };
  Number(int);
    int print();
};

A::A() { }

A::A(enum TYPE Type)
    : type(Type)
{
}

B::B(enum TYPE kind) :
  A(kind)
{
}


Number::Number(int v)
  : B(T_INTEGER),
    intvalue(v)
{
}

int Number::print()
{
    printf("type = %d\n", type); // output: type = 0 (wrong)
    printf("type = %d\n", ((A*)this)->type); // output type = 2 (correct) but why do I need cast?

    switch(((A*)this)->type)
    {
  case T_INTEGER:
    return printf("%d", intvalue);
  case T_FLOAT:
    return printf("%g", floatvalue);
    default:
        assert(0);
    }
}

int main()
{
    Number *n = new Number(2);
    n->print();
    delete n;
}
Foi útil?

Solução

You have declared a member variable

enum TYPE type;

in both class B and A but your B constructor never initialises its own variable with that name - it just passes it to the A constructor which initialises A::type

B::B(enum TYPE kind) :
   A(kind)
{
}

Thus the B member is never initialised. It is not clear why you have added a variable of the same name and type again in the derived class B but my guess is that perhaps you did not intend this and rather just want a single variable of this type in the base class A

When you have this situation with same variable name and type in both a derived and base class, the derived class member shadows the base class member - this is why accessing type from your Number::print() method refers to the B member rather than the A member. Obviously then casting this to A* accesses the A::type member.

Outras dicas

You declared the member variable type in both A and B. But B inherits the member variable type from A. This means every object of type B contains two type variables: A::type and B::type. Since Number is derived from B, it too contains both A::type and B::type. When you use the unqualified name type in a member function of Number, it resolves to B::type since B is lower on the inheritance hierarchy than A. This member is not initialized by your constructors; only A::type is initialized. But ((A*)this)->type refers to A::type. (Side note: prefer static_cast<A*>(this) to (A*)this in this case.)

The solution here is probably to remove the declaration of type from the definition of B. (But I'm not sure what you're trying to do.)

You need to initialize the Number variable type, because that is what you are printing.

Number::Number(int v)
  : B(TYPE::T_INTEGER),
    intvalue(v)
{
    this->type = TYPE::T_INTEGER;
}

Like that, that initializes the local type so it will print 2.

You have to cast because both structs A and B have an attribute with the exact same name and type. How else would the compiler be able to give you the correct value? If you don't cast then you get the one associated with B that you have never initialized, so it is zero just by dumb luck. It is completely separate from the one that is declared/defined within class A. My guess is that the variable in B hides the one in A, and the only way to get to the one in A is to do the cast and explicitly tell the compiler what you want. Get rid of the one in B since you are not setting it anyway, and it should work fine.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top