1

I have a class that has an array of chars as an attribute.

class ClassA{
public:

  ClassA( char *fileName );

  char charArray[13][2];
};

ClassA constructor reads in 26 values from a file, and loads them into charArray as follows.

ClassA::ClassA( fileName ){
   ifstream file;
   file.open( fileName );
   int contactOne, contactTwo;
   int pair=0;

   while( !file.eof() ){
     file >> contactOne;
     file >> contactTwo;
     if( !file.eof() ){
       charArray[pair][0] = (contactOne+65); // convert to Alpha UpperCase
       charArray[pair][1] = (contactTwo+65); // conv to Alpha UpperCase
       pair++;
     }
   }
}

ClassA is initialised in the constructor of another class, ClassB where ClassB contains a pointer to a ClassA object, allowing ClassA to be stored as an attribute of ClassB.

class ClassA; // forward derive
class ClassB{
  public:
  ClassB( char **argv );

  ClassA *a_class
};

ClassB's constructor:

ClassB::ClassB( argv ){
  ClassA a( argv[1] );
  a_class = &a;
}

In main, i'm testing the association of ClassA in ClassB. In a forloop I cout all the values in charArray in the following way.

int main( int argc, char **argv ){
  ClassB b_class( argv );

  for( int i=0; i < 13; i++ ){
     cout << b_class.a_class->charArray[i][0] << endl;
     cout << b_class.a_class->charArray[i][1] << endl;
  }
}

When I construct ClassA outside of ClassB, cout << a.charArray[x][y]; works perfectly, outputting the various uppercase alphabet symbols from charArray.

Indeed, even when I add the cout << a.charArray[x][y]; statement to the ClassA constructor and initialise ClassA using ClassB constructor, the correct values are being loaded into charArray, and the uppercase alphabet symbols are output.

However, when I execute what I have in main, the output from charArray is very strange. The first few values of the array are as expected, but the last values are somewhat random, usually randomly placed blank values and question marks. It is as if, somehow the pointer has caused the values loaded into charArray to be out of the correct range, or I am somehow accessing the wrong memory locations.

Any help would be much appreciated. Am I accessing ClassA in a weird way? Is there a preferred way of having other classes as attributes to some class?

Unusual Output:

A
E
B
J
C
M
D
Z

?
?
?
y

Usual output:

A
E
B
J
C
M
D
Z
F
L
G
Y
H
X
I
V
K
W
N
R
O
Q
P
U
S
T
izaak_pyzaak
  • 890
  • 5
  • 21

1 Answers1

1

ClassA a( argv[1] ); defines a as a local variable that will be destroyed and its memory rendered invalid on exit from the ClassB constructor, leaving a_class pointing at garbage.

Since you need a longer lifespan for a_class you will have to new ClassA(argv[1]); and ensure it is deleted. I recommend looking into std::unique_ptr.

but...

Why do this in the first place? Instead since ClassA has no dependency on ClassB, ClassA can be formally defined or its header file included before ClassB is defined. Then you can remove the forward definition and:

class ClassB{
  public:
  ClassB( char **argv );

  ClassA a_class
};

ClassB::ClassB( argv ):a_class(argv[1]){
}

To make the whole pointer mess go away.

Off topic:

while( !file.eof() ) and its ilk almost never work the way you're expecting. Read more here: Why is iostream::eof inside a loop condition considered wrong?

while( file >> contactOne >> contactTwo ){
    charArray[pair][0] = (contactOne+65); // convert to Alpha UpperCase
    charArray[pair][1] = (contactTwo+65); // conv to Alpha UpperCase
    pair++;
}

Should do what you need.

Community
  • 1
  • 1
user4581301
  • 29,019
  • 5
  • 26
  • 45
  • Thanks. I Tried this. I had to add `ClassA a_class( char *filename)` to the class declaration of `ClassB` not just `ClassA a_class;` Also, how do I then access `charArray` in `main`. Now neither `b_class.a_class.charArray` or `b_class.a_class->charArray` work. – izaak_pyzaak Nov 16 '15 at 22:59
  • My apologies. I missed the forward definition of `ClassA` forcing the use of a pointer. I will update. – user4581301 Nov 16 '15 at 23:02
  • Access from `main` in the non-pointer case would be: `cout << b_class.a_class.charArray[i][0] << endl;` – user4581301 Nov 16 '15 at 23:06
  • `b_class.a_class.charrArray[i][0]` gives the error `b_class.ClassB::charArray does not have a class type`. Whereas `b_class.a_class->charArray[i][0]` gives the error `base operand of -> is not a pointer` – izaak_pyzaak Nov 16 '15 at 23:09
  • Thanks Matteo, however, I thought i'd averted the undefined EOF read in, by reading in a value and then checking if the `eofbit` has been altered before I execute the loop body by use of `if(!file.eof())` /* do loop stuff */` – izaak_pyzaak Nov 16 '15 at 23:16
  • Do not add `ClassA a_class( char *filename)` to `ClassB` as this defined `a_class` as a function that returns `ClassA` rather than a variable of type `ClassA`. To use the non- pointer version `ClassA` must be defined before `ClassB`. If this is not possible you will have to use a pointer-based approach. – user4581301 Nov 16 '15 at 23:24