How do I build a data structure with objects as member variables?

I recently started research that involved coding in cpp which I'm completely new to, and am having trouble with a bunch of stuff:
1. Default constructors
2. Creating a data structure with objects as member variables.

My program setup needs to be like this:
- I need to create a data structure that has one of its member variables as an array of Wave objects: Wave[ ]
- The Wave is actually read from a wave file(My code is linked to some external libraries to do this)
- Each Wave has a GPS object.
- Each GPS object have ~15 member variables of type int or double that.

Question: If you look at my GPS.cpp down below, you will see that I have a default constructor where I initialize all member variables to 0. is there a better way to do this? Should I not initialize to 0? Is it necessary to always have a default constructor?

This is what my GPS.hpp class looks like -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef GPS_HPP_
#define GPS_HPP_

#include <iostream>
#include <fstream>
#include "pulsereader.hpp"
#include "pulsewriter.hpp"

class GPS{

public:
  //possible parameters
  double gpsTime;
  double xAnchor, yAnchor, zAnchor;
  double xTarget, yTarget, zTarget;
  double xDeviation, yDeviation, zDeviation;
  double xFirst, yFirst, zFirst;
  double xLast, yLast, zLast;
  unsigned char edge;
  unsigned char facet;
  unsigned char scanDirection;
  unsigned char intensity;

  PULSEreadOpener pOpener;
  PULSEreader *pReader;
  PULSEscanner scanner;

  GPS();

  void setGPSInformation();
  void writeToFileGPSInformation(std::string fileName);

};
#endif /* GPS_HPP_ */ 


This is my GPS.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
#include "GPS.hpp"

//Default constructor
GPS::GPS(){
  // enter default values
  xAnchor = 0;
  yAnchor = 0;
  zAnchor = 0;
  xTarget = 0;
  yTarget = 0;
  zTarget = 0;
  xFirst = 0;
  yFirst = 0;
  zFirst = 0;
  xLast = 0;
  yLast = 0;
  zLast = 0;
  edge = 0;
  facet = 0;
  scanDirection = 0;
  intensity = 0;
}


void GPS::setGPSInformation(){

  gpsTime = pReader->pulse.get_t();
  // Compute anchor, target and direction
  pReader->pulse.compute_anchor_and_target_and_dir();
  xAnchor = pReader->pulse.get_anchor_x();
  yAnchor = pReader->pulse.get_anchor_y();
  zAnchor = pReader->pulse.get_anchor_z();
  xTarget = pReader->pulse.get_target_x();
  yTarget = pReader->pulse.get_target_y();
  zTarget = pReader->pulse.get_target_z();
  // Compute first and last returning Values
  pReader->pulse.compute_first_and_last();
  xFirst = pReader->pulse.get_first_x();
  yFirst = pReader->pulse.get_first_y();
  zFirst = pReader->pulse.get_first_z();
  xLast = pReader->pulse.get_last_x();
  yLast = pReader->pulse.get_last_y();
  zLast = pReader->pulse.get_last_z();

  edge = pReader->pulse.edge_of_scan_line;
  scanDirection = pReader->pulse.scan_direction;
  facet = pReader->pulse.mirror_facet,
  intensity = pReader->pulse.intensity;
}

/*
 * Writes all GPS information to a csv file
 */
void GPS::writeToFileGPSInformation(std::string fileName){
  long long pulseIndex = 0;
  FILE *scanout;
  scanout = fopen("gps.csv", "w");
  fprintf(scanout, "Pulse Index, GPS Time, X Anchor, Y Anchor,  Z Anchor, \
                    X Target, Y Target, Z Target, X First, \
                    Y First, Z First, X Last, Y Last, Z Last, \
                    edge, Scan Direction, facet, intensity\n");

  pOpener.set_file_name(fileName.c_str());
  pReader = pOpener.open();

  pReader->seek(0);
  while(pReader->read_pulse()) {
    gpsTime = pReader->pulse.get_t();

    pReader->pulse.compute_anchor_and_target_and_dir();
    xAnchor = pReader->pulse.get_anchor_x();
    yAnchor = pReader->pulse.get_anchor_y();
    zAnchor = pReader->pulse.get_anchor_z();
    xTarget = pReader->pulse.get_target_x();
    yTarget = pReader->pulse.get_target_y();
    zTarget = pReader->pulse.get_target_z();

    pReader->pulse.compute_first_and_last();
    xFirst = pReader->pulse.get_first_x();
    yFirst = pReader->pulse.get_first_y();
    zFirst = pReader->pulse.get_first_z();
    xLast = pReader->pulse.get_last_x();
    yLast = pReader->pulse.get_last_y();
    zLast = pReader->pulse.get_last_z();

    edge = pReader->pulse.edge_of_scan_line;
    scanDirection = pReader->pulse.scan_direction;
    facet = pReader->pulse.mirror_facet,
    intensity = pReader->pulse.intensity;

    fprintf(scanout, "%lld,%.8lf,   \
                      %lf,%lf,%lf,  \
                      %lf,%lf,%lf,  \
                      %lf,%lf,%lf,  \
                      %lf,%lf, %lf, \
                      %d,%d,%d,%d,\n", 
            pulseIndex, gpsTime, 
            xAnchor, yAnchor, zAnchor, 
            xTarget, yTarget, zTarget,
            xFirst, yFirst, zFirst,
            xLast, yLast, zLast, 
            edge, scanDirection, facet, intensity) ;
    pulseIndex++;
  }
}


This is a driver class that I'm currently using to write the GPS information to a csv.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include "CmdLine.hpp"
#include "ScannerInformation.hpp"
#include "GPS.hpp"


using namespace std;

int main (int argc, char *argv[]){

  CmdLine cmdLineArgs;
  cmdLineArgs.parse(argc,argv);

  if(cmdLineArgs.printUsageMessage == true){
    std::cout << cmdLineArgs.getUsageMessage() << std::endl;
  }
  else{
    std::string fileName = cmdLineArgs.getInputFileName();
    ScannerInformation scannerInfo;
    scannerInfo.writeToFileScannerInformation(fileName);

    GPS gpsInfo;
    gpsInfo.writeToFileGPSInformation(fileName);

  }

  return 0;
}

Question:Apart from writing the GPS information to a CSV, I want to be able to access each Wave's gps information in my driver class (something like this) -

std::cout << wave.gpsInfo.xAnchor;


Final question:Can you help me with what the data structure looks? Also, how do I write my Wave.hpp and cpp so that it has a GPS object as its member variable, and then how do I access the gps information of a wave object from my driver file?
If you look at my GPS.cpp down below, you will see that I have a default constructor where I initialize all member variables to 0. is there a better way to do this? Should I not initialize to 0? Is it necessary to always have a default constructor?


No it is not always necessary to define and implement a default constructor, the compiler will supply a default no argument constructor until you define and implement any constructor. While you don't always need to initialize all your member variables to zero it is usually considered a good idea. There are several ways to initialize your class member variables. One way is as you have already done, another would be to use an initialization list to initialize the variables, yet another way, if you're using a compiler compiling to the C++11 higher standard, would be to initialize the variables in the class definition. Yet another way would be to call your "set" function from the constructor. And note you should initialize all the variables in the order they are defined in the class definition.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Using initialization list:
Gps::Gps() :   gpsTime(0), xAnchor(0), yAnchor(0), zAnchor(0), etc... 
{
    // Blank body
}

// Directly initializing in the definition:
class GPS{

public:
  //possible parameters
  double gpsTime = 0;
  double xAnchor = 0;
  double yAnchor = 0;
  double zAnchor = 0;
etc...

// Calling a "setter" from a constructor.
Gps::Gps()
{
   // Set the variables to a rational "default" value.
   // Perhaps read the data from a file.
   setGPSInformation();
}


And note that your member variables should usually be in the private section of your class.


Lastly why are you trying to use a C-style file instead of a C++ file stream? C++ streams are much less error prone than C-stdio style functions, IMO.

That makes some things so much clearer! Thank you!

I'm using the c_str() because I believe the constructor for ifstream used to only take a const char * and the c_str() provides that.

Any insight into how I would make the Wave hpp and cpp files so that I can call a Wave object in my driver and access its GPS information?

1
2
3
4
5
6
7
8
9
#include "GPS.hpp"

class Wave {    
private:
  GPS gps;

public:
 //What kind of methods would I use here?
};

I'm using the c_str() because I believe the constructor for ifstream used to only take a const char * and the c_str() provides that.


Where are you using an ifstream?

If you're using one of the more current C++ standards, C++11, or C++14 an ifstream can use a std::string as a parameter.

The following:
1
2
3
4
5
6
  FILE *scanout;
  scanout = fopen("gps.csv", "w");
  fprintf(scanout, "Pulse Index, GPS Time, X Anchor, Y Anchor,  Z Anchor, \
                    X Target, Y Target, Z Target, X First, \
                    Y First, Z First, X Last, Y Last, Z Last, \
                    edge, Scan Direction, facet, intensity\n");

Is using C style file output, you really should be using C++ streams:

1
2
   ofstream scanout("gps.csv"); // Open the output file, erasing contents.
   scanout << "Pulse Index, GPS Time, X Anchor, Y Anchor \n";


Any insight into how I would make the Wave hpp and cpp files so that I can call a Wave object in my driver and access its GPS information?

What's wrong with the approach you have in that snippet? You really haven't provided enough information for me to be able to be of much help in designing your classes.




Topic archived. No new replies allowed.