How to implement classes

Hello, so i am very new to c++ and i have managed to create this code bellow. but i have to use classes to do so. I am very lost how to break this up into classes. I would like to make two classes, an ECG class and RESP class.

could anyone possible help show me how I could do this? thank you!

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int countlines= 0;

void number(){
    countlines--;
    cout << "lines: " << countlines << endl;
};

int main(){
   
    vector<double> data;
    double values, sum = 0.0, max, M;
    string line;
    int i, j, k;
    int N=50;

    
    ifstream rawECGdata;
    ifstream RESPdata;
    rawECGdata.open("ecg.txt");
    RESPdata.open("resp.txt");
    
    if(!rawECGdata.is_open()){
        cout << "error cant open " << endl;
        }
    
    while(rawECGdata >> values){
        countlines++;
        data.push_back(values);
        }
    
    vector<double> filterData(countlines-1);
    int countj = 0;
    for (i=0; i<=countlines; i++)
    {
        for (k=0; k<=N; k++)
        {
            j = (i+k-(N/2));
            if ((j > 0)&&(j<countlines))
            {
                countj++;
                sum = sum + data[j];
            }
        }
        filterData[i] = (1.0/(countj)) * sum;
        sum = 0.0;
        countj = 0.0;
    }
//    for(i=0; i<filterData.size();i++){
//        cout << "filtered data" <<filterData[i] << endl;
//    }
    
    max = *max_element(filterData.begin(),filterData.end());
    cout << "max value: " << max << endl;
    
    M = 0.75 * max;
    cout << M << endl;
    

    vector<int> index;
    vector<double> filterPeaks;

    for (i=1; i<filterData.size(); i++)
    {
        if((filterData[i-1] < filterData[i]) && (filterData[i+1] < filterData[i]) && (filterData[i] > M))
        {
            index.push_back(i);
            filterPeaks.push_back(filterData[i]);
//            cout << i << endl;
        }
    }
    
    int distances [(index.size())-1];
    
    for (i=0; i<index.size(); i++)
    {
        distances[i] = index[i+1] - index[i];
    }

    double sumAve = 0.0;
    double timeInterval = 1.0/(data[0]);
    double averageDist, RR, HR;
    
//    for (i=0; i<(index.size())-1; i++)
//    {
//        cout << distances[i]*timeInterval << endl;
//    }
    
    for (i=0; i<(index.size()-1);i++)
    {
        sumAve = sumAve + distances[i];
    }
    averageDist = sumAve/(index.size()-1);
    
    RR = averageDist*timeInterval;
    HR = 60/RR;
    cout << RR<<endl;
    
    vector<double>abnormal;
    int countab = 0;
    for (i=0; i<(index.size()-1); i++)
    {
        if((distances[i]*timeInterval > 1.2*RR) || (distances[i]*timeInterval < 0.8*RR))
        {
            abnormal.push_back(i);
            countab++;
        }
    }
    
    for (i=0; i<abnormal.size(); i++ ){
        cout << abnormal[i] << endl ;
    }
    cout << countab;
    
//    resp data
//
//
    double RespValues, RespSum = 0.0, RespMax, RespM;
    double RespN = 200;
    int RespCountlines =0;
    
    string RespLine;
  
    vector<double>Data;
    
    if(!RESPdata.is_open()){
        cout << "error cant open " << endl;
        }
    
    while(RESPdata >> RespValues){
        RespCountlines++;
        Data.push_back(RespValues);
        }
    
    vector<double> RespfilterData(RespCountlines-1);
    int RespCountj = 0;
    for (i=0; i<=RespCountlines; i++)
    {
        for (k=0; k<=RespN; k++)
        {
            j = (i+k-(RespN/2));
            if ((j > 0)&&(j<RespCountlines))
            {
                RespCountj++;
                RespSum = RespSum + Data[j];
            }
        }
        RespfilterData[i] = (1.0/(RespCountj)) * RespSum;
        RespSum = 0.0;
        RespCountj = 0.0;
    }
    RespMax = *max_element(RespfilterData.begin(),RespfilterData.end());
    RespM = 0.75 * RespMax;
    
    cout << " resp mx and m" << RespMax << " " << RespM << endl;
    
        vector<int> RespIndexStart;
        vector<double> RespStart;

        for (i=1; i<RespfilterData.size(); i++)
        {
            if((RespfilterData[i-1] < RespfilterData[i]) && (RespM < RespfilterData[i]) && (RespfilterData[i-1] < RespM))
            {
                RespIndexStart.push_back(i);
            }
        }
        
    vector<int> RespIndexEnd;
    vector<double> RespEnd;
        for (i=1; i<RespfilterData.size(); i++)
           {
               if((RespfilterData[i+1] < RespfilterData[i]) && (RespM < RespfilterData[i]) && (RespfilterData[i+1] < RespM))
               {
                   RespIndexEnd.push_back(i);
               }
           }
    
//    for(i=0;i<RespIndexStart.size();i++){
//        cout << RespIndexStart[i]/250.0 << endl;
//    }


    
}




Sorry to ask preliminary questions.

What is this for? Is this schoolwork? Or job work?

Your input files appear to be just a list of textually-formatted floating point values. Is that correct? (Because an .ecg file is a binary format with a bit more information in it than just sample values. I presume you have some other program that first extracts the sample values?)
Hello jtek679,

I would start with "EXC_BAD_ACCESS (code=1, address=0x0)" http://www.cplusplus.com/forum/beginner/269561/ and reread what was said there.

Then maybe you can fix this code so it will compile. What good is to create classes for code that does not compile an run.

You could start with:
http://www.cplusplus.com/doc/tutorial/classes/
https://www.learncpp.com/ Chapter 8
https://www.learncpp.com/cpp-tutorial/82-classes-and-class-members/

Maybe this time you will feel up to sharing the input file so everyone can use the same information and not have to guess.

First I would get the program to compile and run. Then think about what information you want the classes to handle followed by the member functions that will be needed.

Andy

Edit: typo
Last edited on
So i managed to try implement everything but i am getting some error. The ecg.txt and resp.txt are just huge text files like around 8000 lines so im not sure how to add them in. they are all floating points like 0.1-2.5.

when trying to run i get this:

Please enter ecg.txt file then resp.txt file into the arguments.
Reading from file: /Users/joekelly/Library/Developer/Xcode/DerivedData/oopcw33-hevvfcoqwzkjoifgwmcualjyuhom/Build/Products/Debug/oopcw33
libc++abi.dylib: terminating with uncaught exception of type std::length_error: vector

i dont know but it seems there is some error with one of my vectors but i cant find it, and im sure there are more errors too.

main.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
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include "ECG.hpp"
#include "RESP.hpp"


using namespace std;

int main(int argc, char* argv[]){
    
    cout << "Please enter ecg.txt file then resp.txt file into the arguments." << endl;
    
    ECG ecg;
    RESP resp;
    
    
    ecg.openFiles(argv[0]);
    ecg.FilterFunction();
    ecg.HeartRateCalc();
    ecg.AbnormalHeartRate();
    
    resp.openFiles(argv[1]);
    resp.filterFunction();
    resp.startCalc();
    resp.endCalc();
    
    return 0;
}


ecg.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "ECG.hpp"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

int ECG::openFiles(string file){
    
    ifstream rawECGdata;
    rawECGdata.open(file);
    
    if(!rawECGdata.is_open()){
        cerr << "Error opening file!" << endl;
        return -1;
        }
    
    int countlines= 0;
    vector<double> data;
    double values;
    
    while(rawECGdata >> values){
    countlines++;
    data.push_back(values);
    }
    
    cout << "Reading from file: " << file << endl;
    return 0;
};

void ECG::FilterFunction(){
    vector<double> filterData(countlines-1);
    int countj = 0;
    int i, j, k, N=50;
    double sum = 0;
    
    for (i=0; i<=countlines; i++)
    {
        for (k=0; k<=N; k++)
        {
            j = (i+k-(N/2));
            if ((j > 0)&&(j<countlines))
            {
                countj++;
                sum = sum + data[j];
            }
        }
        filterData[i] = (1.0/(countj)) * sum;
        sum = 0.0;
        countj = 0.0;
    }
};

void ECG::peakValue(){
    vector<int> index;
    vector<double> filterPeaks;
    double max, M;
    int i;
    
    max = *max_element(filterData.begin(),filterData.end());
    M = 0.75 * max;

        for (i=1; i<filterData.size(); i++)
        {
            if((filterData[i-1] < filterData[i]) && (filterData[i+1] < filterData[i]) && (filterData[i] > M))
            {
                index.push_back(i);
                filterPeaks.push_back(filterData[i]);
            }
        }
}

void ECG::HeartRateCalc(){
    int distances[index.size()-1];
    double sumAve = 0.0;
    double timeInterval = 1.0/(data[0]);
    double averageDist, RR, HR;
    int i;
        
        for (i=0; i<index.size(); i++)
        {
            distances[i] = index[i+1] - index[i];
        }
        
        for (i=0; i<(index.size()-1);i++)
        {
            sumAve = sumAve + distances[i];
        }
        averageDist = sumAve/(index.size()-1);
        
        RR = averageDist*timeInterval;
        HR = 60/RR;

    cout << "Mean heart rate: " << HR << endl;
};

void ECG::AbnormalHeartRate(){
    vector<double>abnormal;
    int countab = 0;
    int i;
    int distances[index.size()-1];
    double timeInterval = 1.0/(data[0]);
    
    for (i=0; i<(index.size()-1); i++)
    {
        if((distances[i]*timeInterval > 1.2*RR) || (distances[i]*timeInterval < 0.8*RR))
        {
            abnormal.push_back(i);
            countab++;
        }
    }
    cout << "Number of abnormal heartbeats: " << countab << endl;
    cout << "at following heartbeat indices: ";
    for (i=0;i<abnormal.size();i++){
        cout << abnormal[i] << endl;
    }
};


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
#ifndef ECG_hpp
#define ECG_hpp

#include <stdio.h>
#include <vector>
#include <string>

using namespace std;

class ECG {
public:
    
    vector<double> data;
    vector<int> index;
    vector<double> filterData;
    int countlines;
    double RR;
    
    int openFiles(string file);
    void FilterFunction();
    void peakValue();
    void HeartRateCalc();
    void AbnormalHeartRate();
};
#endif /* ECG_hpp */ 


resp.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
#include "RESP.hpp"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>


using namespace std;

int RESP::openFiles(string file2){
//    open the file
    ifstream RESPdata;
    RESPdata.open(file2);
    
    if(!RESPdata.is_open()){
    cerr << "error cant open " << endl;
        return -1;
    }
    
//    find size of file
    while(RESPdata >> RespValues){
    RespCountlines++;
    Data.push_back(RespValues);
    }
    cout << "Reading from file: " << file2 << endl;
    cout << "Sampling Rate is: " << Data[1] << "Hz" << endl;
    return 0;
}

void RESP::filterFunction(){
    for(i=0; i<RespCountlines; i++){
        for (k=0;k<RespN;k++){
            j=(i+k-(RespN/2));
            if((j>0)&&(j<RespCountlines)){
                RespCountj++;
                RespSum = RespSum + Data[j];
            }
        }
        RespfilterData[i]=(1.0/(RespCountj))*RespSum;
        RespSum = 0.0;
        RespCountj = 0.0;
    }
}

void RESP::startCalc(){
    RespMax = *max_element(RespfilterData.begin(),RespfilterData.end());
    RespM = 0.75 * RespMax;
    
    for(i=1; i<RespfilterData.size();i++){
        if((RespfilterData[i-1] < RespfilterData[i]) && (RespM < RespfilterData[i]) && (RespfilterData[i-1] < RespM)){
            RespIndexStart.push_back(i);
        }
    }
    cout << "start of end-exp (in seconds): ";
    
    for(i=0;i<RespIndexStart.size();i++){
        cout << RespIndexStart[i] << endl;
    }
}

void RESP::endCalc(){
    for(i=0;i<RespfilterData.size();i++){
        if((RespfilterData[i+1] < RespfilterData[i]) && (RespM < RespfilterData[i]) && (RespfilterData[i+1] < RespM)){
            RespIndexEnd.push_back(i);
        }
    }
    
    cout << "end of end-exp (in seconds):";
    
    for(i=0;i<RespIndexEnd.size();i++){
        cout << RespIndexEnd[i] << endl;
    }
}


resp.hpp
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
#ifndef RESP_hpp
#define RESP_hpp

#include <stdio.h>
#include <stdio.h>
#include <vector>
#include <string>

using namespace std;


class RESP{
public:
    vector<int> RespIndexEnd;
    vector<double> RespEnd;
    double RespValues, RespSum = 0.0, RespMax, RespM;
    double RespN = 200;
    int RespCountlines =0;
    int i,k,j;
    string RespLine;
    
    vector<double>Data;
    vector<int> RespIndexStart;
    vector<double> RespStart;
    vector <double> RespfilterData;
    int RespCountj = 0;
    

public:
    int openFiles(string file2);
    void filterFunction();
    void startCalc();
    void endCalc();

};

#endif /* RESP_hpp */ 


argv[0] contains the program name.
The first actual command line argument is argv[1].
So you should be passing argv[1] and argv[2].

Your classes are very badly designed.
It is ridiculous to declare what are basically local variables as class members.
Last edited on
Hello jtek679,

In addition to what dutch has already said.

When you run the program from the command line you would type:
programName ecg.txt resp.txt then Enter.

Breaking at the spaces "argv[0]" becomes the full path ending in the program name. "argv[1]" becomes "ecg.txt" and "argv[2]" becomes "resp.txt" and so on if there is more. At the same time "argc" gets the value of 3 because there are three items on the command and the space is the delimiter to separate them.

What that means is that a command line argument that has a space in it needs to be enclosed in double quotes to preserve the space and not use it as a delimiter.

What you need to do with "main" is:
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
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>

#include <algorithm>
#include <fstream>
#include <sstream>

using namespace std;

#include "ECG.hpp"
#include "RESP.hpp"


int main(int argc, char* argv[])
{
	if (argc < 3)
	{
		cout << "\n Please enter ecg.txt file then resp.txt file into the arguments." << endl;

		return 1;
	}

	ECG ecg;
	RESP resp;


	ecg.openFiles(argv[0]);  // <--- Sends program name, with full path, to the open function. Should be "argv[1]".
	ecg.FilterFunction();
	ecg.HeartRateCalc();
	ecg.AbnormalHeartRate();

	resp.openFiles(argv[1]);  // <--- Should be "argv[2]"
	resp.filterFunction();
	resp.startCalc();
	resp.endCalc();

	return 0;
}

I rearranged your includes. I find this to be a help when I miss a need file. The first group tends to be the include files used by any program. The second set is any include file(s) specific to the program and the third set would be any includes in double quotes.

In the first 2 groups is should not make any difference what order they are in as long as they are there. By putting your header files last everything that comes before it should cover anything in your header file.

Looking at the second group of header files not one of them is needed in "main" and could be left out, but would be needed in the other ".cpp" files. When I put a comment on them in "main" the program still compiled with out errors although you still have other problems that need addressed.

Just so you know the "ECG.hpp" file should be more like this.
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
#ifndef ECG_hpp
#define ECG_hpp

//#include <stdio.h>  // <--- C header file and not needed here. Not a replacement for "<iostream>".
//#include <vector>
//#include <string>
//
//using namespace std;  // <--- http://www.lonecpluspluscoder.com/2012/09/22/i-dont-want-to-see-another-using-namespace-xxx-in-a-header-file-ever-again/

class ECG
{
	vector<double> data;
	vector<int> index;
	vector<double> filterData;
	int countlines;
	double RR;

	public:
		int openFiles(string file);
		void FilterFunction();
		void peakValue();
		void HeartRateCalc();
		void AbnormalHeartRate();
};
#endif /* ECG_hpp */ 

My understand is the point of a class is to hide the variables from public access, so that only a member function of the class has access to them. By making them public as you did anything in the program has access and can change the variables. One of the points that dutch is making. This becomes harder to track down when something goes wrong.

Note: A class is private by default where a struct is public by default. Im the above code the first section is considered private until you reach the "public:" line. Then anything after that is "public" until changes by "private" or "protected".

Another thing I found that gives me an error is int distances[index.size() - 1];. VLAs, (Variable Length Arrays), art not legal or allowed in C++. If your compiler allows this it is not doing you any favors. When you create an array, int distances[] what is between the []s needs to be a constant number, This could a variable defined as a constant or a number, but it is a value that must be known at compile time so the compiler can set aside enough space for the array on the stack. If you want to use an expression or a variable for the size then you will have to create dynamic memory on the heap. And do not forget to use "delete" to free the memory when finished.

In the "ECG::AbnormalHeartRate" function you have for (i = 0; i < (index.size() - 1); i++)."i" should be defined in the for loop and the ".size" function returns a "size_t", an alias for "unsigned int". you are better off writing for loops as for (size_t i = 0; i < index.size() - 1; i++). I do not believe the () around "index.size() - 1" are needed, but it will not hurt if you leave them. In your code you are comparing an "int" to an "unsigned int". Not usually a problem, but a potential for one as an "unsigned int" can store a number larger than an "int" can.

One of the points that dutch is saying is in the "RESP" header file int i, k, j; should not be there, but defined in the for loops that use them.

That is what I have found so far.

For the input files I realize that 8000 lines is a lot, but you only need say 100 lines so that everyone can be using the same information. I would guess that the input files were provided to you, so the numbers in those files do have a meaning to the program. Just creating a file of floating point numbers may not produce the correct results as the files you are using.

Even posting a partial file is helpful. Not only will everyone be using the same information they can also see how the file is laid out and my have some suggestion on how to better read the file.

Andy
Topic archived. No new replies allowed.