Quiz program using classes and array of objects

Can someone help me walk through parts of my program?

https://imgur.com/w46sSFX

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

class Question 
{
private: 
	int correctAnswer
	string[5] possibleAnswers
	string questionText

public:
	string GetCorrectAnswer
	int GetCorrectNumber
	string getPossAnswer1
	string getPossAnswer2
	string getPossAnswer3
	string getPossAnswer4
	string getPossAnswer5

	void setQuestionText
	void setPossAnswer1
	void setPossAnswer2
	void setPossAnswer3
	void setPossAnswer4
	void setPossAnswer5
};
#endif 


I've set up the Question.h class as best I can so far. I don't have the accessor or default constructor.

This is more UML to show what types each member needs to be
https://imgur.com/jQ2swrO

This is part of the sample run
https://imgur.com/6RAVJsx

I was hoping if I post the parts of my program I'm having trouble writing someone can walk me through it. I'm really having trouble wrapping my head around most of this.
What is a "method"?
I believe it's the member function of a class isn't it? Don't know if I can explain it in detail and that can be a problem of mine lol
This is what the question.txt file format is supposed to look like

(1) question text?
first possible answer
second possible answer
third possible answer
fourth possible answer
fifth possible answer
x correct answer number.
(2) question text?
first possible answer
second possible answer
third possible answer
fourth possible answer
fifth possible answer
x correct answer number.

(n) question text?
first possible answer
second possible answer
third possible answer
fourth possible answer
fifth possible answer
x correct answer number.

This program I'm doing is supposed to be a quiz program. The program must call a function that reads a set of multiple choice questions from a file, storing the questions in an array of object of the class Question. The class maintains the question text, an array of possible answers, and the correct answer.

After loading the questions, the program should loop through the array prompting the student with the question and checking the student’s answer. The program should indicate “correct” to the student, if the answer is correct, otherwise indicate “incorrect” and display the correct answer.

After all questions have been answered, the program should display the student score in points, and correct score percentage.

This is the int main function I thought I could walk through this one?
int main()
⦁ Declare variables and Question array. Use a constant for the number_of_questions.
1
2
3
int ans;
const int num_of_questions = 5;
string questions[num_of_questions];

⦁ Call initQuestions() function to load array with questions.
 
initQuestions(questions, num_of_questions);

⦁ Use a loop to prompt student with question and read answer.
(Don't know how to do this. I know I should though. I'm trying to run before I can walk basically.)
⦁ Call displayQuestion to display question.
 
displayQuestion();

⦁ use cin >> ans to read student answer.
 
cin >> ans

⦁ If the answer is correct, display correct
1
2
3
if(ans == correctAnswer){
cout << "Correct!" << endl;
}

⦁ Else display incorrect and then display the correct answer.
1
2
3
else{
cout << "Incorrect." << endl;
}

⦁ Increment array index and repeat loop until all questions
⦁ After all questions have been issues, display student results.
1
2
3
cout << "Drill over. Here are the points: " << endl;
cout << "Student Score in points: " << endl;
cout << "Student correct score percentage: " << endl;


That's what I have so far. I know I have a lot of missing parts and fill in the blank areas.
I don't know if I'm asking for too much here. I don't really want the answer but more like an example and to see if what I'm doing is correct or not.
On "method":
I believe it's the member function of a class isn't it?

Correct. How does one must declare a function? Your class definition does not do it correctly.

Declare variables and Question array.

A Question array. Not a string array.

Use a loop

See http://www.cplusplus.com/doc/tutorial/control/
Hmm I know I'm doing it incorrectly but I've been looking up how to declare a function in the class and don't really know how to implement the string type in it. I keep getting errors when I put string in front of something but the UML says it's type is supposed to be string.

Like
 
string questionText
I don’t know if I’m asking for too much here. I don’t really want the answer but more like an example

You aren’t asking too much: the problem is how to give you an example without a working code, since I presume even experienced programmers (and I’m not one of those) need to compile their code to verify if they missed something when they write entire classes.

Here are some hints from my point of view:
Question.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef QUESTION_H
#define QUESTION_H

#include <string>
#include <vector>

struct Question {
    int number {}, // Redundant? Compare with class QuestionManager.
        correct {};
    std::string question;
    std::vector<std::string> answers;
};

#endif // QUESTION_H 


QuestionManager.h:
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
#ifndef QUESTIONMANAGER_H
#define QUESTIONMANAGER_H

#include <fstream>
#include <map>
#include <vector>
#include "Question.h"

class QuestionManager : public Question {
public:
    QuestionManager(std::string in_name_arg = "Quiz.dat");
    void readQuestions();                                   // could be private
    bool state() const;
    void askQuestions(unsigned start_from_arg = 0);
    void displayResults() const;

private:
    bool file_read {false};
    int score {},
        howmany {};
    size_t start_from {};
    std::string in_name;
    std::ifstream in;
    std::map<int, Question> qs;
    void displayQuest(const int index) const;
    int getIntFromUser() const;
};

#endif // QUESTIONMANAGER_H 


QuestionManager.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
#include <cstdio> // for std::perror()
#include <iostream>
#include <iterator>
#include "QuestionManager.h"

QuestionManager::QuestionManager(std::string in_name_arg)
    : in_name {in_name_arg}
{
    readQuestions();
}

void QuestionManager::readQuestions()
{
    in.open(in_name);
    if(!in.is_open()) { ... }
    
    for(std::string line; std::getline(in, line); /**/ ) {
        if(in.bad()) {
            // manage reading errors;
        }
        if(line.at(0) == '(') {                         // question found
            // Extract first number.
            // This must become Question::number and QuestionManager::qs.first
            ...
            Question q;
            q.number = i;

            // Extract question
            ...
            q.question = line;

            // Extract answers
            for(i=0; i<5; i++) {
                ...
                q.answers.push_back(line);
            }

            // Extract correct answer
            ...
            q.correct = i;

            if(!qs.insert(std::make_pair(q.number, q)).second) {
                // manage errors in file (duplicated questions)
                ...
            }
        }
    }
    in.close();
    file_read = true;
}

bool QuestionManager::state() const
{
    return file_read;
}

void QuestionManager::askQuestions(const unsigned start_from_arg)
{
    // control if question is in range
    ...
    start_from = start_from_arg == 0 ? 1 : start_from_arg;
    for(auto it=qs.find(start_from); it!=qs.end(); ++it) {
        displayQuest(it->first);
        int ans = getIntFromUser();
        if(ans == it->second.correct) {
            ...
            score++;
        } else {
            ...
        }
        howmany++;
    }
}

void QuestionManager::displayQuest(const int index) const
{
    std::cout << "\nQuestion for student:\n---------------------\n"
              << qs.at(index).number << ") "
              ...
}

int QuestionManager::getIntFromUser() const
{
    int answer {}; // answer can't be 0
    do {
        std::cout << "Please enter your (I hope correct) answer: ";
        std::string line;
        std::getline(std::cin, line);
        try {
            answer = std::stoi(line);
        } catch 
        ...
        if(answer < 1 || ...
    } while(answer == 0);
    return answer;
}

void QuestionManager::displayResults() const
{
    std::cout << "\nThe quiz is over. Here are your points:\n"
                 ...
}


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
#include <iostream>
#include <limits>
#include "QuestionManager.h"

void waitForEnetr();

int main()
{
    QuestionManager qm;
    if(qm.state()) {
        qm.askQuestions(9);
        qm.displayResults();
    } else {
        std::cout << "Cannot execute program.\nExiting now.\n";
    }
    waitForEnetr();
    return 0;
}

void waitForEnetr()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}


Quiz.dat:

(9)A ___ is a member function which is automatically called when an object is ___.
destructor, created
constructor, created
static function, deallocated
utility function, declared
none of the above
2
(10)The constructor return type is:
int
float
char
structure pointer
none of the above
5

Okay I see what you mean on needing working code. So I wrote my own. But now I'm having trouble specifically with a few things. Thank you very much for helping me :)

Here is my header file.
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
#ifndef QUESTION_H
#define QUESTION_H

#include<string>

class Question
{
private:
	int correctAnswer;
	std::string questionText;
	std::string possibleAnswers[5];

public:

	std::string getCorrectAnswer();
	int getCorrectNumber();
	std::string getPossAnswer1();
	std::string getPossAnswer2();
	std::string getPossAnswer3();
	std::string getPossAnswer4();
	std::string getPossAnswer5();
	std::string getQuestion();

	Question();
	void setCorrect(int);
	void setPossAnswer1(std::string);
	void setPossAnswer2(std::string);
	void setPossAnswer3(std::string);
	void setPossAnswer4(std::string);
	void setPossAnswer5(std::string);
	void setQuestionText(std::string);
};

Question::Question() // default constructor
{
	questionText = "";
	correctAnswer = 0;
}

void Question::setQuestionText(std::string question)
{
	questionText = question;
}

void Question::setPossAnswer1(std::string ans)
{
	possibleAnswers[0] = ans;
}

void Question::setPossAnswer2(std::string ans)
{
	possibleAnswers[1] = ans;
}

void Question::setPossAnswer3(std::string ans)
{
	possibleAnswers[2] = ans;
}

void Question::setPossAnswer4(std::string ans)
{
	possibleAnswers[3] = ans;
}

void Question::setPossAnswer5(std::string ans)
{
	possibleAnswers[4] = ans;
}

void Question::setCorrect(int n)
{
	correctAnswer = n;
}

std::string Question::getCorrectAnswer()
{
	int rightIndex = correctAnswer - 1;
	return possibleAnswers[rightIndex];
}

int Question::getCorrectNumber()
{
	return correctAnswer;
}

std::string Question::getPossAnswer1()
{
	return possibleAnswers[0];
}

std::string Question::getPossAnswer2()
{
	return possibleAnswers[1];
}

std::string Question::getPossAnswer3()
{
	return possibleAnswers[2];
}

std::string Question::getPossAnswer4()
{
	return possibleAnswers[3];
}

std::string Question::getPossAnswer5()
{
	return possibleAnswers[4];
}

std::string Question::getQuestion()
{
	return questionText;
}

#endif 


Here is my .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
#include<iostream>
#include<string>
#include<iomanip>
#include<fstream>
#include "Question.h"

using namespace std;

void initQuestions(Question* q, int num_q)
{
	// open questions.txt
	ifstream f;
	f.open("Questions.txt");
	if (!f.is_open()){
		// print error
		cout << "File did not open!" << endl;
		exit(1);
	}
	int i = 0;
	while (i < num_q){
		q[i] = Question(); // make a new Question object
		// read in info on one question, starting with question text
		string text;
		getline(f, text);
		q[i].setQuestionText(text);
		getline(f, text);
		q[i].setPossAnswer1(text);
		getline(f, text);
		q[i].setPossAnswer2(text);
		getline(f, text);
		q[i].setPossAnswer3(text);
		getline(f, text);
		q[i].setPossAnswer4(text);
		getline(f, text);
		q[i].setPossAnswer5(text);
		getline(f, text);
		int correct = stoi(text);
		q[i].setCorrect(correct); 		// set info in q[i] accordingly.
		// read in answers
		i++;
	}
}
//Define a function(displayQuestion())) that  displays the question text and possible answers.
void displayQuestion(Question q)
{
	cout << q.getQuestion() << endl;
	cout << "Enter the Correct Answer: \n";

}
int main()
{
	cout << "Welcome to My Awesome Quiz-o-Matic!" << endl;
	// Declare variables and Question array. Use a constant for the number_of_questions
	int ans = 0;
	int nWrong = 0;
	int nRight = 0;
	const int num_of_questions = 5;
	Question questions[num_of_questions];
	cout << "Question for Student\n";
	cout << "____________________\n";

	//Call initQuestions() function to load array with questions.
	initQuestions(questions, num_of_questions); //fills the array with information

	//Use a loop to prompt student with question and read answer.
	for (int i = 0; i < num_of_questions; i++)
	{
		//Call displayQuestion to display question.
		displayQuestion(questions[i]);

		//use cin >> ans to read student answer.
		cin >> ans;

		//If the answer is correct, display correct
		// refer to specific question object
		if (ans == questions[i].getCorrectNumber())
		{
			cout << "Correct!" << endl;
			nRight++;

		}
		//Else display incorrect and then display the correct answer.
		else
		{
			cout << "Sorry that's Incorrect. The correct answer is: " << endl;
			nWrong++;
		}

	}
	//After all questions have been issued, display student results.
	cout << "Drill over. Here are the points: " << endl;
	cout << "Student Score in points: " << nRight << endl;
	cout << "Student correct score percentage: " << int((nRight*1.0 / num_of_questions) * 100) << endl;

	system("pause");
	return 0;
}


And here is how my text file looks:
<1> Objects are created from abstract data types that encapsulate ______ and _____ together.
ANSWERS:
1. numbers, characters
2. data, functions
3. addresses, pointers
4. integers, floats
5. None of these
2

<2> In OOP terminology, an object's member variables are often called its _____, and its member functions are sometimes referred to as its behaviors, or _____.
ANSWERS:
1. values, morals
2. data, activities
3. attributes, activities
4. attributes, methods
5. None of these
4

<3> A C++ class is similar to one of these
ANSWERS:
1. inline function
2. header file
3. library function
4. structure
5. None of these
4

<4> Examples of access specifiers are the keywords
ANSWERS:
1. near and far
2. opened and closed
3. private and public
4. table and row
5. None of these
3

<5> The constructor function's return type is
ANSWERS:
1. int
2. float
3. char
4. structure pointer
5. None of these
5

Now it compiles and runs but I need help with the displayQuestion(); function and how to get it to display each question and answer options.
The program clearly calls displayQuestion().
The displayQuestion() displays the value returned by q.getQuestion().

You do say that the program runs. Does it display the five questions as you expect?
My (personal and debatable) point of view is:
a) decide which data you need and possibly group them together.
For example:
1
2
3
4
5
6
7
8
9
10
11
12
#include <string>
#include <vector>

class Question
{
private:
    int correctAnswer {};

    std::string questionText; // text of the question

    // Let's keep it simple: std::vector are far easier to use than C-style arrays
    std::vector<std::string> possibleAnswers;


Now you have two options: read that block of data from file one by one or read the entire file once at the beginning and store all the data into a container.
I would opt for the second choice (that’s how my example above was conceived), but you can stick to your idea and read one block at each step. Let’s get on this way.

b) Decide which operation you want to perform on the data:
If you want to read one block of data each step, at every step you need to check:
- if the file is open
- if there’re data left inside the file.
You also need to inform the caller about any error.

So:
firstly, open the file; report on errors:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <fstream>
. . .

class Question
{
private:
    . . .
    std::ifstream quiz;
    
    // If the caller wants to check file status
    bool is_quiz_opened {false};

public:
    Question(std::string filename = "Quiz.dat");
    int openQuizFile(const std::string& filename);  // needed in case of opening
                                                    // failure while constructing
                                                    // an instance of the class
    bool getIsQuizOpened() const;


Secondly, read one block of data from file.
(You can also decide to read first block automatically, as soon as an instance of the class is defined or the opening function is called.)
1
2
3
4
    int readFromQuizFile();     // return:  0 - error reading
                                //          1 - data read
                                //         -1 - EOF
                                // Note: what's above is just an example 


Thirdly, display data on screen:
1
2
3
4
#include <iostream>
    . . .
    void printQuestion() const;
    friend std::ostream& operator<<(std::ostream& os, const Question& rhs);


Nearly finished: provide correct answer if requested:
 
    std::string getCorrectAnswer() const;


Finally, check if answer is correct:
 
    bool isAnswerCorrect(int answer) const;


Apart from closing the input file, I think your class shouldn’t be supposed to do other things.
All other steps should be delegated to the caller.
For example:
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
int main()
{
    Question q; // tries to open "Quiz.dat"
    // Let's suppose the constructor does NOT call readFromQuizFile():
    int howmany {}, // total asked questions
        guessed {}; // total correct answers received
    while(1 == q.readFromQuizFile()) { // basic check
        q.printQuestion();
        std::cout << "Please enter your answer: ";
        int answ {};
        std::cin >> answ; // not the best way to read from console
        if(q.isAnswerCorrect(answ)) { 
            std::cout << "Good!\n";
            guessed++;
        } else {
            std::cout << "Disaster! Correct answer is " << q.getCorrectAnswer()
                      << '\n';
        }
        howmany++;
    }
    std::cout << "Your score is: " << guessed << " out of " << howmany
              << ", i.e. " << static_cast<double>(guessed) / howmany * 100
              << "%.\n";
    return 0;
}


I can understand what I'm saying is not easy to follow, but I don't know how to describe it without adding the working code :-)
You do say that the program runs. Does it display the five questions as you expect?


No unfortunately it only displays the first question line but no options for the answers.

It will display
<1> Objects are created from abstract data types that encapsulate ______ and _____ together.


But it won't display
ANSWERS:
1. numbers, characters
2. data, functions
3. addresses, pointers
4. integers, floats
5. None of these


I can understand what I'm saying is not easy to follow, but I don't know how to describe it without adding the working code :-)


No what you're saying makes a lot of sense when I can see code as well. Thank you very much :)
No unfortunately it only displays the first question line but no options for the answers.

This is your code. What does it do, exactly?
1
2
3
4
5
void displayQuestion(Question q)
{
	cout << q.getQuestion() << endl;
	cout << "Enter the Correct Answer: \n";
}
when I can see code as well
My attempts to solve your issues (the one which reads the entire file once and the other which reads block by block) are at your disposal as soon as you want to have a look at them.
I haven’t post them just because you clearly stated you want to make it by your own.
Topic archived. No new replies allowed.