Troubles calling functions; vector of pointers

Getting to the point, I have a vector of pointers inside a seperate Exam class.
vector <Question* > question_list
The Question class is my base class in which I have derived sub classes for the different types of questions (MultipleChoice, LongAnswer, etc.). I am using my vector to hold the different types of questions.

in each of those classes I have virtual "write" functions in both the base and the derived classes, that write to a file differing for each type of question.
My problem now is calling the write function from a Exam function. I've tried several methods, such as:
1
2
3
4
	for (size_t i = 0; i < question_list.size(); i++)
	{
		question_list[i].write(testfile.c_str());
	}

but it comes with two errors: "error C2228:left of '.write' must have class/struct/union" along with "IntelliSense: expression must have class type"

I have made a write function for the exam class as well but am not sure what it should include since the Exam class is not a derived class of the Question class.
your question_list[i] statement will return Question* type.
Imagine following code:
1
2
Question* x = new Question();
x.write(...);

It will not compile too.
Use pointer member selection operator or dereference your pointer before use.
Last edited on
I have tried *(question_list+i).write(filename);, along with other variations still doesn't work properly.

I've also tried using iterations I researched like the code below:
1
2
3
4
5
6
	string testfile = "exam.txt";
	vector<Question *>::iterator citer;
	for (citer = question_list.begin();citer != question_list.end(); citer++)
	{
		(*citer)->write(testfile.c_str());
	}

but i get errors for testfile.c_str() as the following:

Error 1 error C2664: 'Question::write' : cannot convert parameter 1 from 'const char *' to 'std::ostream &' c:\users\adam\documents\uk - spring - 2013\cs 215-008\source control\cs215\asal227\pa3\pa3\exam.cpp 61 1 pa3

2 IntelliSense: initial value of reference to non-const must be an lvalue c:\users\adam\documents\uk - spring - 2013\cs 215-008\source control\cs215\asal227\pa3\pa3\exam.cpp 61 19 pa3
a) you could use question_list[i] -> write(testfile.c_str());
b) show write function declaration.
I've used that as well and it gives the following errors:
1
2
3
Error	2	error C2039: 'write' : is not a member of 'std::vector<_Ty>'

Error	1	error C2819: type 'std::vector<_Ty>' does not have an overloaded member 'operator ->'


I'm not sure what to put in the write function for my Exam class, since it is not inherited from the Question base class or any of its inherited classes. I need it to simply call the write methods from the vector type. Do I need to make the write virtual or pure virtual?
show full code.
Exam class at current state
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
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include "Exam.h"
#include "Question.h"
#include "MultipleChoice.h"
#include "ShortAnswer.h"
#include "LongAnswer.h"
#include "CodeQuestion.h"

// used for randomizing and seeding (HINT section of PA3)
#include <algorithm>
#include <ctime>
#include <cstdlib>

using namespace std;

Exam::Exam(int min, int max, int total)
	: min_chapt(min),max_chapt(max),tot_questions(total)
{
	vector<Question* > question_list;
}

//Exam::~Exam()
//{
//	//delete question_list;
//	//free questin_list vector!!(dynamically alocated questions)
//}

//opening the file,
//reading the lines in a loop, allocating a new question object for each
//line, and putting pointers to those objects into the vector.  If you
//want, it can be in this method that you skip questions from the wrong
//chapters (so they never end up in the vector at all).
void Exam::read_questions(string filename)
{
	ifstream infile;
	infile.open(filename.c_str());
	// Check for failure after opening
	while (infile.fail())
	{
		cout << "I'm sorry, that file name is incorrect." << endl;
		cout << "Please enter the name of the question pool file: ";
		cin >> filename;
		infile.open(filename.c_str());
	}
	cout << "Correct!" << endl << endl; //filename was 

	string line;
	while(infile)
	{
		getline(infile,line);
		question_list.push_back(parse_question(line));
	}
	string testfile = "exam.txt";
	//vector<Question *>::iterator citer;
	//for (citer = question_list.begin();citer != question_list.end(); citer++)
	//{
	//	(*citer)->write(testfile.c_str());
	//}
	for(size_t i = 0; i < question_list.size(); i++)
	{
		question_list->write(testfile.c_str());
	}

}


//MUST RETURN VALUE
//int Exam::question_random() const
//{
//	//Go over "hint" section in PA3
//}

void Exam::write(ostream &out) const
{


}
		
void Exam::write_key(ostream &out) const
{

}

//PRIVATE!!
vector<string> Exam::split_string(string input)
{
	vector<string> pieces;

	// Start of the current field
	int field_start = 0;

	// Location of the next at sign.
	int next_at;
	do {
		// Find the @.  Returns the index, or string::npos if it wasn't
		// found.
		next_at = input.find('@', field_start);

		// If it wasn't found, add the last piece.
		if (next_at == string::npos)
			pieces.push_back(input.substr(field_start));
		// Or it was found, so add this piece
		else
			pieces.push_back(input.substr(field_start, next_at - field_start));

		// The next field starts just after the @
		field_start = next_at + 1;

		// If there was no @, we're done.
	} while(next_at != string::npos);

	return pieces;
}


//PRIVATE!
Question* Exam::parse_question(string line)
{
	string type, text;
	int points, chapter;

	vector<string> fields = split_string(line);

	type = fields[0];

	// Convert the integer fields.
	istringstream iss(fields[1]);
	iss >> points;
	iss.str(fields[2]);
	iss >> chapter;

	text = fields[3];

	// Now use the type to convert the rest.
	if (type == "short") {
		// Everything else is an answer.
		vector<string> answers;
		for (size_t i=4; i<fields.size(); i++)
			answers.push_back(fields[i]);
		return new ShortAnswer(points, chapter, text, answers);
	} 
	// Need an else if(...) {} for every type.
	else if (type == "multiple"){
		vector<string> answers;
		string location = fields[5];
		for (size_t i=6; i < fields.size(); i++)
			answers.push_back(fields[i]);
		return new MultipleChoice(points, chapter, text, location, answers);
	}
	else if (type == "long"){
		string answer = fields[4];
		return new LongAnswer(points, chapter, text, answer);
	}
	else {
		vector<string> answer;
		for(size_t i = 4; i < fields.size(); i++)
			answer.push_back(fields[i]);
		return new CodeQuestion(points, chapter, text, answer);
	}
}
Line 65: change question_list->write(testfile.c_str()); to question_list[i] -> write(testfile.c_str());
Line 77: Exam::write takes ostream parameter, not char* as you calling it.
for Line 77, how do I go about fixing this error?
pass ostream (possibly ofsteam) as a parameter. You already know how to use files for input, do the same for output.
Thank you for all of your help.
but now that i have that problem working I am prompted with a new error for the following code
1
2
3
4
5
6
7
8
9
	ifstream infile;
	infile.open(filename.c_str());

	string line;
	while(infile)
	{
		getline(infile,line);
		question_list.push_back(parse_question(line));
	}


I'm curious if it has to do with my constructor which I initialize the question_list vector as simply vector<Question* > question_list;

the error states:
1
2
3
Debug Assertion Failed!
........
Expression:vector subscript out of range


I ran the debugger and it is putting the different question types inside the vector, and runs the while loop until the last line
vector<Question* > question_list;
You are not initializating it here, you are creating local variable which will be immediatly destroyed.
I've tried multiple ways to initialize it but can't seem to resolve the issue. do I simply set it to some large integer?
vector<Question*> question_list; needs to be in the class declaration:

1
2
3
4
5
class Exam {
public:
    vector<Question*> question_list;
...
};
.

Alternatively, you can put it in the global scope (ie outside of the class declaration)
I had it as a data member.
also, once putting vector <Question*> question_list; into the class declaration, the problem is still present.

I found the problem!!
my while loop was grabbing the null terminator
here is the fix
1
2
3
4
5
6
7
	while(infile)
	{
		getline(infile,line);
		if (line != "")
			question_list.push_back(parse_question(line));
		
	}
Topic archived. No new replies allowed.