i have a class which named class nameAndLastname and it has a
class nameAndLastname
{
private:
vector<string> Names_Lastname();
public:
void get();
void Delete();
string search();
};
private:vector<string> Names_Lastnames(); and at first i got some names from another function and put them in vector<string> Names_Lastnames()
void nameAndLastname::get()
{
int SizeOFNames;
cout<<"enter number of the names and last names";
cin>>SizeOFNames;
vector<string> Names_Lastnames(SizeOFNames);
ifstream inFile;
ofstream outFile;
string fileName,Line;
cout<<"whats the file name?:";
cin>>fileName;
inFile.open(fileName);
getline(inFile,Line);
cout<<"the first line of the file is:"<<endl;
cout<<Line<<endl;
cout<<"outputfilename?"<<endl;
cin>>fileName;
outFile.open(fileName);
outFile<<Line<<endl;
cout<<"now enter the names and last names";
for (int i=0; i<=SizeOFNames; i++) {
getline(cin,Names_Lastnames[i]);
outFile<<Names_Lastnames[i]<<endl;
}
inFile.close();
outFile.close();
}
and now i want to delete one of the names that user want to delete and i write this
void nameAndLastname::Delete(){
string rname;
cin>>rname;
auto itr = find(Names_Lastnames.begin(), Names_Lastnames.end(), rname);
if (itr != Names_Lastnames.end()) Names_Lastnames.erase(itr);
//error~>Reference to non-static member function must be called; did you mean to call it with no arguments?
//Use of undeclared identifier 'Names_Lastnames'
}
but i have this error "Reference to non-static member function must be called" .
i want to know how can i access to my vector from class named class nameAndLastname with reference
You have declared Names_Lastnames as a function that takes no parameters and returns a vector<string>.
(You did not put anything into it - if it looks like you did, you put your names into a vector with the same name.)
Remove the parentheses to make it a vector<string>.
Like this
class nameAndLastname
{
private:
vector<string> Names_Lastname; // <--- no ()
public:
void get();
void Delete();
string search();
};
void nameAndLastname::get()
{
int SizeOFNames;
cout<<"enter number of the names and last names";
cin>>SizeOFNames;
Names_Lastname.resize(SizeOFNames); // <--- resize class vector
...
}
void nameAndLastname::Delete(){
string rname;
cin>>rname;
auto itr = find(Names_Lastname.begin(), Names_Lastname.end(), rname);
if (itr != Names_Lastname.end())
Names_Lastname.erase(itr);
}
As is common for newbies you had multiple mistakes and misunderstandings ganging up on you.
This version declares the vector (correctly without ()) in the class where all methods can access it, and resizes that vector (instead of redeclaring it) in the get method
void nameAndLastname::get()
{
//...
vector<string> Names_Lastnames(SizeOFNames);
//..
} // the scope of Names_Lastnames ends here.
It seems like, you are referring a member variable with a similar name:Names_Lastname. If yes, correct it. Then if Names_Lastname is the variable, it is declared like a function in the class body. The parenthesis is not required. Hope you will try and repost the question if required.
Related
trying to do a project for class, but keep getting the error: no instance of overloaded function matches argument list relating to the implementation of the rows vector. the area that is specifically highlighted is the . operator before push_back and insert.
void holdLines(ifstream in, vector<string> rows) {
string line;
string prevLine;
vector<string> rows;
int lineNumber = 0;
int vectorNumber = 0;
while(true) {
getline(in, line);
if(in.fail()) {
break;
}
lineNumber++;
vectorNumber = lineNumber - 1;
rows.push_back(lineNumber);
rows.insert(prevLine, line);
}
}
You are trying to pass an integer to push_back when a string is required.
It also looks like your local variable "rows" is named the same as your parameter "rows".
http://www.cplusplus.com/reference/vector/vector/push_back/
Your compiler is correct: there is no overload of std::vector<std::string>::push_back that accepts an int, because a std::vector<std::string> stores std::strings, not ints.
It's quite unclear from code alone what you are trying to do, due to the myriad mistakes, but start by replacing your push_back call with something sensible.
There is no method insert with two parameters of type std::string as you are trying to call
rows.insert(prevLine, line);
Also it is not clear what you are trying to do in this statement.
Edit: After you updated yor code nevertheless this statemenet
rows.push_back(lineNumber);
also is wrong because the rows is declared as a vecto of strings. It is not a vector of int and moreover class std::string does not have an appropriate constructor.
But in any case the function does not make sense because you declared a local variable with the same name as the second parameter and tried to fill this local vector that will be deleted after exiting the function
void holdLines(ifstream in, vector<string> rows) {
^^^^^^^^^^^^^^^^^^
string line;
string prevLine;
vector<string> rows;
^^^^^^^^^^^^^^^^^^^^
//..
I think the function should be declared either like
void holdLines(ifstream in, vector<string> &rows);
^^^
or like
vector<string> holdLines(ifstream in);
Take into account that instead of this statements
while(true) {
getline(in, line);
if(in.fail()) {
break;
}
//...
you could write
while ( getline( in, line ) )
{
//...
If you need simply to fill the vector that is passed as the argument then the function can look the following way
void holdLines( std::ifstream &in, std::vector<std::string> &rows )
{
std::string line;
while ( std::getline( in, line ) ) rows.push_back( line );
}
So I have this class:
The purpose of this class is to change the post fix algebraic expression (1234*+-) to infix expression (1*2+3-4).
class PostfixExpression
{
private:
string postfix;
vector<string> tokenizedEx;
double result;
void tokenizeStr(); // Where do I call this?
public:
PostfixExpression(string p);
//mutators, and accessors for string and double only
//no accessor and mutator for vectors
string changeToInfix() const;
};
PostfixExpression::PostfixExpression(string p)
{
setPost(p);
}
//mutators, and accessors
void PostfixExpression::tokenizeStr()
{
stringstream ss(postfix);
tokenizedEx.clear();
string hold;
int i = 0;
while (ss >> hold)
{
tokenizedEx.push_back(hold);
}
}
//....
The purpose of the private class tokenizeStr() is to tokenizing the string and put it into the vector<string> tokenizedEx.
For example, in my main, I would have
int main()
{
PostfixExpression test("1 2 3 4 * + -");
}
Now I am trying to tokenize the string and update it to the vector<string> tokenizedEx via the private member function tokenizeStr().
After tokenized, each element in the vector should either contain an integer or an operator, but I can't seem to find a way to call the function.
I know it is totally illegal to call private member functions from main since the function is private.
Any suggestions is appreciated.
Your setPost method does what? Setting the postfix member?
You can call tokenizeStr() in the constructor, right after calling setPost.
I see a changeToInfix() method in your class which you haven't shown the implementation of. That method should be the one calling tokenizeStr().
I have a question on the pointer used by string in a function. my code is below.
void printName(int *max,int *min,string *maxFirst, string *maxLast)
{
ifstream infile;
infile.open("input.txt");
string firstName,lastName;
float age;
infile>>firstName>>lastName;
while(firstName!="Term") {
infile>>age;
if(age==*max)
{
maxFirst=&firstName;
maxLast=&lastName;
cout<<*maxFirst<<' '<<*maxLast<<endl;
}
}
To use this function, in main(), I define it like
int main()
{
void printName(int *,int *,string *,string *);
int *pMaxAge, *pMinAge;
string *maxFirst,*maxLast;
pMaxAge=&maxAge;
pMinAge=&minAge;
printName(pMaxAge,pMinAge,maxFirst,maxLast);
cout<<"\nThe oldest employee is "<<*maxFirst<<' '<<
*maxLast<<endl;
}
I skip some part of my code. While the first cout works fine, the second one doesn't work. Is there any problem with my pointer passing please?
Thanks.
Your understanding of pointers is a complete mess. You should go and RTFM on pointers, from the ground up. Nothing you do here makes sense.
First you declare 4 pointers, not initialized to anything. Then you pass them to a function which takes pointer arguments by value, and expect changing the pointers' values to affect anything outside the function.
You should allocate these variables in your main function, and then pass them either by reference or by address, and assign to them properly when doing so.
For instance:
void printName(int *max,int *min,string *maxFirst, string *maxLast)
{
ifstream infile;
infile.open("input.txt");
string firstName,lastName;
float age;
infile>>firstName;
while(firstName!="Term") {
infile>>lastName>>age;
if(age==*max)
{
*max = (int)age;
*maxFirst=firstName;
*maxLast=lastName;
cout<<*maxFirst<<' '<<*maxLast<<endl;
}
infile>>firstName;
}
}
int main()
{
int MaxAge = 0, MinAge;
string maxFirst,maxLast;
printName(&MaxAge,&MinAge,&maxFirst,&maxLast);
cout<<"\nThe oldest employee is "<<maxFirst<<' '<<
maxLast<<endl;
}
In the printName function you need to assign to the content of the pointer:
*maxFirst = firstName;
*maxLast = lastName;
You also need to pass pointers to the existing variables as function arguments:
string maxFirst;
string maxLast;
printName(pMaxAge, pMinAge, &maxFirst, &maxLast);
The same probably applies to the integer arguments.
My code is already working, seen here: http://pastebin.com/mekKRQkG
Right now, my functions work but utilizing information that I've declared globally, I guess, and I want to convert them so that they are in the format as seen on lines 11-15, but I'm unsure of how to convert them to do so. Simply put, I'm trying to convert my function of
"void add_county_election_file"
to be in the format of
"void add_county_election_file(const string, const vector &, const vector &, const vector &, const vector &)"
and I have no idea where to begin or how to even start.
Could someone please help me out and show me how I'd do this for the first function, so I can implement it across the board?
Thanks guys!
Your function declaration should look something like this:
void add_county_election_file(const string, vector<int>&, vector<string>..);
Make sure that your argument list for the vector template is correct(that's the type you put between <>)
Then match the implementation of you function to the declaration:
void add_county_election_file(const string, vector<int>&, vector<string>..){...}
Now call your function with apppropriate arguemtns in main:
string s;
vector<int> arg;
vector<string> sv;
void someFunction (s, arg, sv ...);
I think you are doing correct as the function you have declared
void add_county_election_file(const string, vector<int>&, vector<int>&,..);
so you just have to call the above function with the required arguments, as right now you are not passing the argument and your current definition doesn't accepts any arguments.
And as a good practice, in your int main() function you can use switch rather than going for if else.
Store your variables and functions in a class, overload operators and create functions to access these variables.
Declare all variables in int main() and set parameters to be passed into each function e.g.
void print_results() is modified to become
void print_results(std::vector<int> vec, int nCount, etc..)
Similar to the first one, create a struct to hold all data members, then pass the struct(by ref) into each function.
struct CountryTracker
{
std::vector<int> ID;
std::string name;
//etc...
}
`void print_results(CountryTracker& Obj) //pass single struct into functions`
The OOP way to do this is to create a class called perhaps ElectionInfo, where:
These would be its member fields:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
and these would be its member functions:
void add_county_election_file(const string);
void search_county(const string);
void print_results();
This way you don't have to pass the references to the vectors around at all, instead you can just do:
ElectionInfo an_elect_info;
char selection = get_menu_choice();
// some if-statements to decide which of the following to call:
an_elect_info.add_county_election_file(county_name);
an_elect_info.search_county(county_name);
an_elect_info.print_results();
But if you'd prefer to stay with the current functional approach:
Declare and initialize the following inside your main method:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
The syntax for the commented out function declarations should be tweaked to look like this:
void add_county_election_file(const string, vector<string>&, vector<int>&, vector<int&, vector<int>&);
(Of course, the definition should follow suit)
You would invoke it like this:
add_county_election_file(countyname, countyNameVector, countyNCount, countyFCount, countyOCount);
Objects are automatically passed-by-reference.
The basic process of refactoring should at the first step involve only code grouping and placement and should only minimally involve writing new logic. Using this as a principle you can go about modifying the code in the following way at first.
string ReadInputString(const char* title)
{
string s
cout << title;
cin >> s;
}
void add_county_election_file(const std::string& filename
, std::vector<string>& countyNameVector
, std::vector<int>& countyNCount
, std::vector<int>& countyFCount
, std::vector<int>& countyOCount
)
{
int NCount = 0;
int FCount = 0;
int OCount = 0;
int NTotal = 0;
int FTotal = 0;
int OTotal = 0;
char vote;
std::ifstream input((filename).c_str());
string countyName;
if(input.is_open())
{
input >> countyName;
countyNameVector.push_back(countyName);
while(input >> vote)
{
if(vote == 'N' || vote == 'n')
{
NCount = NCount + 1;
}
else if(vote == 'F' || vote == 'f')
{
FCount = FCount + 1;
}
else
{
OCount = OCount + 1;
}
}
countyNCount.push_back(NCount);
countyFCount.push_back(FCount);
countyOCount.push_back(OCount);
}
cout << countyName << endl;
}
void add_county_election_file()
{
string fn = ReadInputString("Enter the county file to process: ");
add_county_election_file(fn,g_countyNameVector,g_countyNCount,g_countyFCount,g_countyOCount);
}
As you can see I have just extracted your code and moved them to individual functions and changed names to make some significance. Like in the function ReadInputString - the line "cin >> s" was originally "cin >> filename". The abstract name "s" is to signify that the ReadInputString has no knowledge or doesn't care what the semantic meaning of the string it is reading from console.
In order to not change your main function - I have added a overloaded add_county_election_file that calls one function followed by another. The idea is that you should keep something unchanged and change others (for good) and then alternate if need be.
And I have changed names of your global variable to differentiate them from the local variable using "g_" - the point is that "g_" should only be found at very few places in your code.
This if for my homework.
I have a class called Student that takes 3 parameters (id, name, class) and I want to store each student in an array called Roster (which can only have 7 students).
The user will provides input to add or remove students. Thus, I have to manage the array by creating or deleting students. So if the user specify the student ID, I have to remove him for the array.
I tried to use a fixed array, but I'm struggling to make it works. Is there a better way to implement this?
I must not use a vector or any STL container.
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
static const int SIZE = 7;
class Student {
private:
int student_id;
std::string name;
std::string classification;
public:
Student(int, std::string, std::string); // constructor; initialize the list to be empty
~Student();
void print();
};
#endif
student.cpp
#include <iostream>
#include <string>
#include "student.h"
#define PROMPT "class> "
using namespace std;
Student::Student(int a, string b, string c){
student_id = a;
name = b;
classification = c;
}
Student::~Student(){
//delete Student
}
void Student::print(){
cout<<"Enrolled:"<<endl;
cout<<student_id<<"-"<<name<<"-"<<classification<<endl;
}
main.cpp
#include <iostream>
#include <string>
//#include <sstream>
#include "student.h"
#define PROMPT "class> "
using namespace std;
//**** Implement Error Handling ****\\
enum errorType {
UNKNOWN_ERROR,
INPUT_ERROR,
HANDLER,
NUM_ERRORS
};
// error messages
string errorMessage[NUM_ERRORS] = {
"Unknown Error\n",
"Input Error\n",
};
// error handler
void handleError(errorType err) {
if(err > 0 && err < NUM_ERRORS)
cout<< "Error: "<< errorMessage[err];
else cout<< "Error: "<< errorMessage[UNKNOWN_ERROR];
}
//**** END Error Handling ****\\
void enroll(Student newStudent){
cout<<"test";
Student roster[SIZE];
for(int i=0;i<SIZE;i++){
newStudent->roster[i];
}
}
void handleInput() {
int id; string n, c;
cin>>id>>n>>c;
Student newStudent(id,n,c);
newStudent.print();
enroll(newStudent);
//cout<<"hello3"<<endl;
return;
}
int main() {
//Student newStudent; /* <-- why doesn't this work?!*/
string input = "";
bool finished = false;
cout<<PROMPT; // prompt the user
while(!finished) {
if(input!="") cout<<PROMPT;
cin>>input;
if(input=="enroll") {
cout<<PROMPT<<"Enroll student:"<<endl;
handleInput();
}
else if(input=="drop") {
cout<<PROMPT<<"Enter ID:"<<endl;
}
else if(input=="roster") {
cout<<"This will print formatted list of students"<<endl;
}
else if(input=="quit") {
finished=true;
}
else handleError(errorType(1));
}
}
Since it is a homework, I'd like to point out some mistakes you did because it is important to understand what you are doing in the first place.
You must not program by coincidence, but by trying to understand exactly what's going on. By doing that you will become better and better and the answers should fall in place.
What you've done
So, from what you are describing, the array is fixed. Thus it is a good idea to use a constant as you did (SIZE).
However, as we can see below you a declaring an array of size SIZE in the function. By doing that, your array is like a temporary variable, because its scope is inside the function. Each time you call this function, the array will be declared again and then deleted at the exit. So it should be declared outside.
void enroll(Student newStudent)
{
cout<<"test";
Student roster[SIZE]; // Here 'roster' will be available only inside the function.
for(int i=0;i<SIZE;i++)
{
newStudent->roster[i]; // Here there is few mistakes see my explanation below*
}
}
If we look at this part:
newStudent->roster[i];
First of all, the arrow '->' is used with pointers. The dot '.' is used with objects. In both case, it does the same thing, access to public members of Student.
Since you passed
void enroll(Student newStudent)
you should use '.' instead.
newStudent.SomeOfYourMembers;
If the parameter was a pointer to a Student
void enroll(Student *newStudent)
Then, you'd have to use the arrow '->' like you did.
Back to the original statement:
newStudent->roster[i];
This means, you want to access to 'roster' array at position 'i' inside your Student object (newStudent). As you can see in your code, roster is not declared inside Student (and should not be since you want an array of Students), so that won't work.
Guidelines
As I mentionned, your array should be outside the function, so at a higher scope.
Then, if you need an array of student, basically, 'roster[i]' will give you access to the student 'i'. Thus, if you want to print the student, you would do something like that:
roster[i].print();
This would be valid because 'print()' is defined as public.
In order to store a student inside the array, you can do something like:
roster[i] = new Student(0 /* id*/, "name", "classification");
But don't forget, each time you use new, you have to balance it with a delete. And if you are creating the student like this in a loop, you will have to clean them the same way:
for(int i = 0; i < SIZE; ++i)
{
delete roster[i];
}
Good luck!
Don't hesitate if there is there anything that I could clarify. I hope this helps!
Edit: In reply to your first comment.
Concerning the roster array
No, it is not mandatory to create a class roster you could declare roster in the main.cpp.
The key concept is that by defining
Student roster[SIZE];
the array will contains objects of type Student.
What roster[i].print() means is that you are printing one of the Student of that array, in fact the one at position 'i'.
Concerning the print() function
What is powerfull with Object Oriented language, each object will have the same print() function. So, you do not need to convert the array to string.
However, if you want a string to be printed out (or returned) you can write the code inside the print() function that will do this job.
The advantage of this, is that if further on you need to change your array in some ways, your print() function will always work.
Concerning the Delete
When you are doing something like this on an array that contains objects:
delete roster[i];
It will delete the object at the position 'i'. Thus, the destructor of that Student 'i' will be called. If your object Student would contains other object, you would have to delete them in the destructor.
Further notices
Since ID is an input that you are storing into a string, you will have to convert the ID to the same type of the student_id, which is a int. Then you can always write a loop for each student and check their ID to delete the proper one.
Concerning the container, a fixed array might not be the best to achieve this job. You might want to look the LinkedList concept.
It doesn't make much sense for enroll to be a member function, so
I'd wrap the roster into a class to get automatic clean up of my
pointers.
#include <cstddef>
struct Student {};
class Roster
{
private:
static const size_t size = 7;
// non-copyable
Roster(const Roster&);
Roster& operator=(const Roster&);
public:
Roster() {
for(unsigned i = 0; i < size; ++i) {
roster_[i] = NULL;
}
}
~Roster() {
for(unsigned i = 0; i < size; ++i) {
delete roster_[i];
}
}
// enroll by copy
bool enroll(const Student& s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = new Student(s);
return true;
}
}
// out of space
return false;
}
// enroll by taking ownership
bool enroll(Student* s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = s;
return true;
}
}
// out of space
return false;
}
private:
// data
Student* roster_[size];
};
int main()
{
Roster r;
Student s;
r.enroll(s);
Student* sp = new Student();
r.enroll(sp);
return 0;
}
What about this?
Student * roster[2];
roster[0] = new Student(5,"first","2A");
roster[1] = new Student(2,"Second","5B");
Ps:
Enrol and Size shouldn't be members of the student class.
Print should ideally be externalized and a ToString function should be added instead.
You should use the inline constructor initialization instead:
Student(int a,string b,string c):id(a),name(b),class(c){}
You've used the keyword class as a variable name of type string. You shouldn't do that. Does it even compile like that?
enroll should have two arguments: void enroll( Student enrollee, Student Roster[]). You should probably change the name of Roster to roster because it's not a class and typically class names are capitalized.
If your array will only ever have 7 students then you could use some sentinel value to mark that the current student as an invalid student. Perhaps the id will be -1 to mark this. It means basically that you need some way to keep track of which spots in the array you can still use. If you don't do this then declaring an array of Students will get you an array of students with garbage member variables. You wouldn't be able to tell which students are real ones and which are just place holders for when someone new enrolls in the class. I would create a default constructor of Student and initialize its member variables like this:
id=-1;
name="";
name_of_class="";
I changed the name of your string class to avoid confusion.
After all that, enroll would look something like this:
void Student::enroll( Student enrolee, Student roster[]){
//search through roster to check for the first student with an
//id of -1
//if there are no students with id of -1, produce an error message
//that the class is full
//overwrite the student with id of -1 with the id, name, and
//name_of_class of enrollee
}
Although I'm not sure what exactly string class is there for. Does it store what class the Student is in? Is it their year in school like Freshman, Sophomore?
If you're suppose to use dynamic allocation of roster, though, it's a different story, but you said it will only ever have seven students.