Exam Prep Question

Hi all... i've been given the following prep question (20 Marks):

//START

Background: Your work for a company trying to save hte world from a mutant invasion. The president has ordered you to write a program to keep track of all the mutants, their powers, and their threat levels.

- You must write either a struct of a class named mutant_info. This class/struct should be written in a file named mutant_info.h. Note: In your class/struct you may only use one public/private label.

- Member_info has 3 private members, namely string name, string power and int level. You must create 3 constructors: a default constructor that initializes name to Wolverine, power to Regeneration, and level to 10; a constructor that takes two strings and and int as input parameters; and a constructor that takes an input stream as an input parameter.

- You must create an accessor and a mutator function (a function that sets a member to a new value) for each private member.

- Also, write a file "main.cpp". You should include a function that will increase a vector of type vector<mutant_info> with an unknown number of elements and display all of the entries.

//END

Okay, obviously the first 2 points tell you to make a struct or a class.. i think i've done this correctly?:

1
2
3
4
5
6
7
class mutant_info
{
    private:
           Member_info() : name("Wolverine"), power("Regeneration"), level("10"){}
           std::istream& read(std::istream&);
           void function(std::string, std::string, int&);
};


But what about a mutator function? And a function that
will increase a vector of type vector<mutant_info> with an unknown number of elements


Please help me out.. Would be appreciated.
Thanks
All of the member functions that you are tasked to write need to be public (which you are not doing) All of the data members, per assignment, must be private (none of which you've actually declared).

Recall that default access in a class is private, so you are asked to do something like this:

1
2
3
4
5
class mutant_info {
    // Private data members here; default access is private
  public:
    // Member functions and constructors here
};


The syntax for declaring a constructor is

 
mutant_info( /* put your parameters here */ );


ie, the "name" of the constructor "function" is the name of the class itself. Your default constructor above is correct except that you've named it Member_info, not mutant_info (and you haven't declared name, power, or level as data members of the class).

An accessor function generally has the form:

1
2
3
   return_type getSomeParameterName() const {
         return that_parameter;
   }


You'll have to replace return_type, SomeParameterName, and that_parameter with the correct values.

A mutator method generally has the form

1
2
3
void setSomeParameterName( const TypeOfParameter& newValue ) {
    that_parameter = newValue;
};


You'll again have to replace my generic wording.

jsmith, am I on the right track?

Here's my mutant_info.h coding:

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
/mutant_info.h

#ifndef _GUARD_mutant_info
#define _GUARD_mutant_info

#include <iostream>
#include <iomanip>
#include <ios>
#include <string>

class mutant_info
{
 	  private:
	  		  std::string name;
	  		  std::string power;
	  		  int level;
	  		  
	  public:
           	  mutant_info() : name("Wolverine"), power("Regeneration"), level(10){}
           	  std::istream& read(std::istream&);
           	  void function(const std::string, const std::string, const int);
           	  
};

#endif 


and here's my main.cpp coding:

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
//main.cpp

#include "mutant_info.h"

#include <cstdlib>
#include <iostream>
#include <vector>
#include <fstream>
#include <string>

using namespace std;

void loadDB()
{
// Getting it wrong here... start:
   		   
// 	 vector<mutant_info>
 	 string nameDB, powerDB;
 	 int levelDB;
 	 
 	 ifstream infile("db.txt");
 	 while (infile >> nameDB >> powerDB >> levelDB)
 	 	   read(infile);
 	 	   vector<mutant_info> 
// :end
}

void setName(const string b)
{
 	 name = b;
}

void setPower(const string a)
{
 	 power = a;
}

void setLevel(const int c)
{
 	 level = c;
}

string getName() const
{
     return name;
}

string getPower() const
{
     return power;
}

int getLevel() const
{
 	 return level;
}

istream& read(istream& in)
{
     in >> name >> power >> level;
     return in;
}

int main()
{
 	system("CLS");
 	
 	cout << " Alien list\n\n";
 	
 	string name, power;
 	int level;
 	
 	cout << "Enter alien name: ";
 	cin >> name;
 	
 	cout << "Enter alien power: ";
 	cin >> power;
 	
 	cout << "Enter alien level: ";
 	cin >> level;
 	
 	vector<mutant_info> store;
 	
    system("PAUSE");
    return 0;
}


I know i'm getting it wrong at loadDB() and i'm not too sure how to get main() going properly...

Thanks again for the help.
Last edited on
Lines 28/33/38/43/48/53 all define functions that are not members of mutant_info for two reasons: 1) you haven't declared the accessor/mutator functions in mutant_info in the header file, and 2) the implementations need mutant_info:: in front of the function name to indicate to the compiler that they are the implementations of the class members.

main() should look something like (in pseudo-code):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main() {
    vector<mutant_info> store;
    do {
         mutant_info mutant;

         // Ask user to enter name, and read input
         // Set the mutant's name using the mutator method

         // Ask user to enter power and read input
         // Set ...

         // Ask ...
         // Set ...

         // Now that mutant is filled out, put it onto the vector (store).

         // Ask user if they want to enter another
      } while( user answered yes );

      // Now loop through all of the elements in store and output them.
}
Here's the revised version:

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
int main()
{
 	vector<mutant_info> store;
 	char c;
 	
 	do
 	{
        mutant_info mutant;

	 	system("CLS");
	 	
	 	string name, power;
	 	int level;
	 	
	 	cout << "Enter alien name: ";
	 	mutant.read(cin);
	 	mutant.setName(name);
	 	
	 	cout << "Enter alien power: ";
	 	mutant.read(cin);
	 	mutant.setPower(power);
	 	
	 	cout << "Enter alien level: ";
	 	mutant.read(cin);
	 	mutant.setLevel(level);
 	
 		vector<mutant_info> store = mutant;
 	
 	cout << "\nMutant added.\n";
 	

 	cout << "Would you like to add another? (Y\\N)";
 	cin >> c;
	}
	while (c == 'Y' || c == 'y');
 
 	for (vector<mutant_info>::const_iterator iter = store.begin(); iter != store.end(); ++iter)
	 	cout << " Alien list\n\n";
 		cout << "Mutant Name: " << mutant.getName() << " has the power " << mutant.getPower()
 			 << " at level " << mutant.getLevel() << "\n";
	
    system("PAUSE");
    return 0;
}


but i'm getting an error

"conversion from `mutant_info' to non-scalar type `std::vector<mutant_info, std::allocator<mutant_info> >' requested"

on line 27

and another error

" 'mutant' undeclared (first use this function) "

on line 39...

So close to the end... :)
For the first problem, look at
http://cplusplus.com/reference/stl/vector/push_back.html
for how to insert elements into a vector.

On the second problem, you are attempting to access the object you declared within your do{}while() block. 1. that declaration is only valid within that code block, and 2. you should be using your iterator within that for loop anyways.
Last edited on
Thanks jRas, noob mistake i'll admit... still learning...

The first problem, thanks to you, i've sorted out with store.push_back(mutant);.

The second problem i'm not too familiar with the coding...

1
2
3
4
 	for (vector<mutant_info>::const_iterator iter = store.begin(); iter != store.end(); ++iter)
	 	cout << " Alien list\n\n";
 		cout << "Mutant Name: " << iter.getName() << " has the power " << iter.getPower()
 			 << " at level " << iter.getLevel() << "\n";


I understand the way it's meant to work such that it grabs the members from the different methods but the wording isn't working..

In a map i would use: cout << iter->second.getMember() << endl; but again, i'm not sure about vectors.
 
iter->getName();  // etc 


All types of iterators on the different containers work the same way. Dereferencing them using -> or * gives you access to the element that the iterator "points" to.

In the case of maps, say std::map< int, char >, what is actually stored in the map is a std::pair< int, char >. std::pair is a very simple struct that looks like

1
2
3
4
5
6
7
8
// omitting some details here...
template< typename T1, typename T2 >
struct pair {
    pair( const T1& t1, const T2& t2 ) : first( t1 ), second( t2 ) {}
  private:
    T1 first;
    T2 second;
};


In the map case, -> returns a std::pair.
Thanks jsmith, changed wording as per your instructions...

Can you explain to me why this is happening now:

http://img27.imageshack.us/my.php?image=ummmd.jpg

I'm assuming it's got something to do with the istream method?

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
istream& mutant_info::read(istream& in)
{
     in >> name >> power >> level;
     return in;
}

int main()
{
 	vector<mutant_info> store;
 	char c;
 	
 	do
 	{
        mutant_info mutant;

	 	system("CLS");
	 	
	 	string name, power;
	 	int level;
	 	
	 	cout << "Enter alien name: ";
	 	mutant.read(cin);
	 	mutant.setName(name);
	 	
	 	cout << "Enter alien power: ";
	 	mutant.read(cin);
	 	mutant.setPower(power);
	 	
	 	cout << "Enter alien level: ";
	 	mutant.read(cin);
	 	mutant.setLevel(level);
 	
 		store.push_back(mutant);
 	
 		cout << "\nMutant added.\n";
 	
		cout << "Would you like to add another? (Y\\N)";
		cin >> c;
	}
	while (c == 'Y' || c == 'y');
 
 	for (vector<mutant_info>::const_iterator iter = store.begin(); iter != store.end(); ++iter)
	{
	 	cout << " Alien list\n\n";
 		cout << "Mutant Name: " << iter->getName() << " has the power " << iter->getPower()
 			 << " at level " << iter->getLevel() << "\n";
    }
    system("PAUSE");
    return 0;
}
mutant_info::read takes one input and puts it in name, power, and level. You just want to set one at a time, so it should be 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
 	do
 	{
        mutant_info mutant;

	 	system("CLS");
	 	
	 	string name, power;
	 	int level;
	 	
	 	cout << "Enter alien name: ";
                getline(cin, name)
	 	mutant.setName(name);
	 	
	 	cout << "Enter alien power: ";
	 	getline(cin, power)
	 	mutant.setPower(power);
	 	
	 	cout << "Enter alien level: ";
	 	cin >> level
	 	mutant.setLevel(level);
 	
 		store.push_back(mutant);
 	
 		cout << "\nMutant added.\n";
 	
		cout << "Would you like to add another? (Y\\N)";
		cin >> c;
	}
	while (c == 'Y' || c == 'y');
Last edited on
Wow, this is a shock to the system...

@Gumbercules
mutant_info::read takes one input and puts it in name, power, and level.


I was under the impression in >> name >> power >> level; was the same as saying

1
2
3
in >> name;
in >> power;
in >> level;


asking the user for a different input every time and not pushing the same input into the 3 members...

So then, when referring to my orginal prep question requirement:

and a constructor that takes an input stream as an input parameter.

How would i have to word it such that this requirement has been accomplished?

Would this be a way?

1
2
3
4
5
cout << "Enter alien name, power and level: ";
mutant.read(cin);
mutant.setName(name);
mutant.setPower(power);
mutant.setLevel(level);
The read method you have defined in your mutant_info class is not a constructor. Also, your use of the read and set methods combined together is incorrect.

As your code is written, You prompt for the alien name, then call read() which receives input for all three members in the class (not just the name), then the setName method which passes in the value of the local string name, but that local string is never assigned a value. This process is then repeated for power and level, which cause a lot of redundant and out of sequence input.

Gumbercules code removes the read() calls, inputs the values into the local variables, then passes those variables into the appropriate set method. Prompt for name, set name. Prompt for power, set power. Prompt for level, set level.

As for your 3 constructors: Constructors are defined using the same name as the class itself. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class myClass{
    std::string str1;
    int myVal;
  public:
    myClass() : str1("abc"), myVal(25){} //Default constructor
    myClass(std::string a, int c): str1(a), int(c){} //Constructor with string and int as input parameters
    myClass(std::istream&); //Constructor with input stream param.
};


//Caution should always be taken when using streams to construct objects
//There are more potential pitfalls with this kind of constructor than other constructors
//This simple example is perfect example of how NOT to use them, but that's beyond the scope of this thread
myClass(std::istream& in){
  in >> str1 >> myVal;
}


The constructor only gets called when an instance of the class is created, it's not a class method you explicitly call yourself. Which constructor gets called depends on how the object is instantiated (ie, the constructor that gets called is the one that matches the input parameters provided at the time of construction).

mutant_info mutant; calls the default constructor, since no input parameters are provided. This method requires you use your set methods to set the class members to the appropriate values prior to inserting them into your vector. (unless you want to insert an object set to the default values as defined in the constructor)

Alternatively, you could push the object into your vector this way store.push_back(mutant_info(name, power, level));. This method uses the constructor that takes two strings and an int as input parameters. You would prompt the user for the three values, than execute this call, passing those values in.

And to use your third constructor, store.push_back(mutant_info(cin));. This constructor prompts for the input values within the constructor itself, and so your external variables are not used.

There's actually a forth constructor getting used in your code as well. When you call store.push_back(mutant);, push_back is making a copy of mutant and inserting that copy into the vector. This is done using the copy constructor, which the compiler will define for you if you don't explicitly define it yourself.
Last edited on
Topic archived. No new replies allowed.