I'm learning C++ from the book Primer C++.
Differently from what I used to do in Java, I learnt that is good practice defining classes and classes' methods' prototypes in a header file.
So I did it, following step by step the book, implementing the methods and constructors in a .cpp file.
The result is an endless amount of error reports.
Student.h
#ifndef STUDENT_H_
#define STUDENT_H_
class Student{
private:
string firstname;
string lastname;
double gpa;
public:
Student();
Student(string fname,string lname, double aGpa);
~Student();
void Show();
double getGpa();
};
#endif
On compile returns the following errors:
unknown name type "class"
expected { etc etc after the Student
attribute (of course, since it can't understand it's a class)
I also tried to include the cstring and the string library (both couldn't be found by the compiler, I suppose because it's something only a .cpp file can access) ending with using the library, but that didn't change a thing.
Student.cpp
#include <iostream>
#include <cstring>
#include "student.h"
using std::cout;
using std::cin;
using std::endl;
Student::Student(){
cout << "Default constructor called\n";
cout << "No info regarding the student. Object not initialized";
}
Student::Student(string fname,string lname, double aGpa){
this->firstname=fname;
this->lastname=lname;
this->gpa=aGpa;
}
void Student::Show(){
cout << lastname <<", " << firstname <<"\nGPA: " << gpa << endl;
}
double Student::getGpa(){
return this->gpa;
}
Student::~Student(){
cout<< "Object student has been destroyed";
}
On compile returns the following errors
string (in student.h) does not name a type (even if I include string.h)
in Student.h, expected ')' before fname (in the constructor declaration)
in Student.cpp, expected constructor before '(' token (in the constructor declaration)
In function Show(), lastname and firstname etc are not declared in this scope (but GPA is apparently)
I don't know about your compiler errors, but your header file is missing something to use the std::string:
#include <string>
using std::string;
are your sure you use a c++ compiler and not a c compiler?
Related
So I am a CS student working on a project for exception handling (Try/catch). My teacher told us to implement the sstream library so we could use it in a class that outputs a message that includes a passed parameter of type int. For some reason unknown to me, when I use it, or even when I declare a variable of type stringstream, it causes a compile error with error message:
"copy constructor of 'tornadoException' is implicitly deleted because field 'ss' has a deleted copy constructor"
Here is my code. I am at a loss.
main.cpp
#include <iostream>
#include <string>
#include <sstream>
#include "tornadoException.h"
using namespace std;
int main()
{
try{
int tornado = 0;
cout << "Enter distance of tornado: ";
cin >> tornado;
if(tornado > 2){
throw tornadoException(tornado);
}
else{
throw tornadoException();
}
}
catch(tornadoException tornadoObj){
cout << tornadoObj.what();
}
}
tornadoException.cpp
#include <iostream>
#include <string>
#include <sstream>
#include "tornadoException.h"
using namespace std;
tornadoException::tornadoException(){
message = "Tornado: Take cover immediately!";
}
tornadoException::tornadoException(int m){
ss << "Tornado: " << m << "miles away!; and approaching!";
message = ss.str();
}
string tornadoException::what(){
return message;
}
tornadoException.h
#ifndef tornadoException_h
#define tornadoException_h
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class tornadoException{
public:
tornadoException();
tornadoException(int m);
string what();
private:
stringstream ss;
string message;
};
#endif
Alright, figured out the error but I'll leave up this post since I couldn't find the answer anywhere else. The problem was that I declared the stringstream buffer as a private variable in the class. The buffer needs to be declared locally within the function declaration it is being used in, in this case right before the loading of the buffer in the implementation file:
tornadoException::tornadoException(int m){
stringstream ss;
ss << "Tornado: " << m << " miles away!; and approaching!";
message = ss.str();
}
stringstream has a deleted copy constructor, which means that a stringstream object cannot be copied.
Since your tornadoException class has a stringstream variable, this means that your class cannot be copied either.
In your main function, you capture the exception by value, which means that you are copying it into the tornadoObj variable - which is not allowed.
Try changing the line
catch(tornadoException tornadoObj) to catch(tornadoException& tornadoObj) so that you're getting a reference to the exception instead of a copy of it.
This is actually a general rule: An exception shall always be caught by reference, not by copy: Core Guidelines E.15
I'm trying to finish a C++ school assignment and I have a question that I have an issue that may be simple. I have constructed all the files (more than below which felt was unnecessary to add) from scratch and I am left scratching my head. I'm told to create a private dynamic array of objects that will be defined by user input. This will be in the "student.cpp" file. This dynamic array is to create the objects that will operate the "course.cpp" file. I have attempted a large series of workarounds, but have not found the answer and expect the answer to be obvious. Here is the trimmed down version of my code. I also commented where the issue is in the student.cpp file and the other points of possible issue.
Any suggestions will be appreciated. I manually typed this again, so if it appears there was a typo, my apologies in advance. I will edit if I notice anything after the initial post.
//source.cpp
#include <iostream>
#include "student.h"
using namespace std;
void main() {
student stu;
stu.printRecord();
}
//student.h
#ifndef STUDENT_H
#define STUDENT_H
#include<iostream>
#include<string>
#include "course.h"
using namespace std;
class student{
public:
student();
void printRecord();
~student();
private:
string name;
int numCourses;
course* stuCourses; //possible source of error
};
#endif
//student.cpp
#include "student.h"
student::student(){
cout << "enter name: ";
getline(cin,name);
cout << "Enter the number of courses the student is taking: ";
cin >> numCourses;
course* stuCourses= new course[numCourses]; //possible source of error (now this->stuCourses = new course[numCourses];)
}
void student::printRecord(){
cout << endl << name << endl;
course::printCourse(); //Error at this point
}
//course.h
#ifndef COURSE_H
#define COURSE_H
#include <iostream>
using namespace std;
class course{
public:
course();
void printCourse();
~course();
private:
string title;
};
#endif
//course.cpp
#include <iostream>
#include "course.h"
course::course(){
cout << "Title: ";
cin >> title;
}
void course::printCourse(){
cout <<title;
}
course::~course(){}
Again, any help is appreciated. Thanks for looking even if you don't respond.
class course{
public:
course();
void printCourse();
~course();
private:
string title;
};
Here you defined printCourse as a non-static-method of the class course.
But where the error occurs: course::printCourse() you're trying to execute a static method of the class Course. If you don't know what I'm talking about here is a short summary (but i recommend reading about the differences between static and non static methods):
A static method works without an instance of the class. This is commonly used on singletons which are by design "just one single object". This could be for example a global ID-Counter for the students:
class StudentIdManager
{
static int num_students = 0;
public:
static int getNextStudentId()
{
return num_students++;
}
}
You can now get the next unique id for a student by calling StudentIdManager::getNextStudentId() without an actual object. You could call it a "class function". Not an "object function".
A static class is obviously not suitable for your course, so it makes sense for your to implement it like you did.
However, you have to call it on an actual object. The difficulty is to find each object in the dynamically allocated array, but you should have every info you need. In the end it would look something like this:
void student::printRecord()
{
cout << endl << name << endl;
for (size_t i = 0u; i < numCourses; i++)
{
// here you're now calling the method printCourse on an actual course as intended instead of a static class
stuCourses[i]->printCourse();
}
}
However I also find it weird that you have to implement this. A simple std::array<course, numCorses> for a fixed number of courses, or a std::vector<course> for a variable number of courses would make the code way more readable, safe and extensible.
What you're doing here would is a nice task for C to get used to the Von Neuman Architecture.
But not for C++. It's not the same. Sadly for most teachers C++ is "C with classes" which is just wrong on so many levels. All the features C++ added where there for you to not write code like your teacher wants.
Instead of:
course* stuCourses= new course[numCourses];
Can use:
this->stuCourses = new course[numCourses];
Or even:
stuCourses = new course[numCourses];
I'm new to C++, and for a school assignment we have to create a base class and create 2 derived classes from it, then display the output of all the associated functions of the two derived classes.
The problem is, when I try to include the two derived classes in my test file, only the one that I include first works. If I reverse the order that I include them, then the one that's now included first works, but the second one doesn't
Any ideas why this might be happening?
Here's my test file:
#include "Payment.h"
#include "CashPayment.h" // This one will work
#include "CreditCardPayment.h" // This one won't. Unless you switch them
#include <iostream>
#include <string>
using namespace std;
// Tests the CashPayment and CreditCardPayment classes, derived from the Payment clas
int main() {
CashPayment firstCash(420);
cout << "First Cash Payment" << endl
<< "Amount: " << firstCash.getAmount() << endl
<< firstCash.paymentDetails() << endl;
CreditCardPayment firstCredit("Mingwu Chen", 123456789, 11, 2016, 100);
cout << "Number: " << firstCredit.getNumber() << endl
<< "Month: " << firstCredit.getMonth() << endl
<< "Year: " << firstCredit.getYear() << endl
<< "Amount: " << firstCredit.getAmount() << endl
<< firstCredit.paymentDetails() << endl;
}
Here's my CashPayment.h file:
#ifndef CASHPAYMENT_H
#define CASHPAYMENT_H
#include <string>
#include "Payment.h"
using namespace std;
class CashPayment: public Payment {
public:
// Creates a CashPayment with an amount of 0
CashPayment();
// Creates a CashPayment with the given amount
CashPayment(double a);
// Creates a string out of all the CashPayment details
string paymentDetails();
};
#endif
Here's the CreditCardPayment.h file:
#ifndef CASHPAYMENT_H
#define CASHPAYMENT_H
#include <string>
#include "Payment.h"
using namespace std;
class CreditCardPayment: public Payment {
private:
string name;
int cardNumber;
int expMonth;
int expYear;
public:
// Creates a CreditCardPayment with an amount of 0
CreditCardPayment();
// Creates a CreditCardPayment with the given card holder name, card number, expiry month, expiry year, and amount
CreditCardPayment(string n, int c, int m, int y, double a);
// Creates a string out of all the CreditCardPayment details
string paymentDetails();
// Returns the card holder name
string getName();
// Returns the card number
int getNumber();
// Returns the expiry month
int getMonth();
// Returns the expiry year
int getYear();
// Sets the card holder name t0 the given name
void setName(string n);
// Sets the card number to the given number
void setNumber(int c);
// Sets the expiry month to the given month
void setMonth(int m);
// Sets the expiry year to the given year
void setYear(int y);
};
#endif
Here's the Payment.h file:
#ifndef PAYMENT_H
#define PAYMENT_H
#include <string>
using namespace std;
class Payment {
private:
double amount;
public:
// Creates a Payment with an amount of 0
Payment();
// Creates a Payment with the given amount
Payment(double a);
// Returns the amount
double getAmount();
// Sets the amount to the given value
void setAmount(int a);
// Creates a string out of all the Payment details
string paymentDetails();
};
#endif
I've been up all night trying to figure this out, and I'm offically stumped. Any ideas or suggestions at all with be greatly appreciated.
(PS: Many people on here don't seem to like using namespace std, but that's what my teacher wants)
Both header files have:
#ifndef CASHPAYMENT_H
#define CASHPAYMENT_H
As such, whichever one is included first, is the one whose contents actually get compiled.
#ifndef CASHPAYMENT_H
#define CASHPAYMENT_H
(stuff)
#endif
This is called the include-guard, and it stops a file being included more than once when the program is compiled.
You shouldn't have CASHPAYMENT_H on all three header files - each file needs a unique include-guard. It doesn't actually matter what, as long as it's unique in your project, and the header filename in uppercase is a good convention for this.
As an alternative to #ifndef, you can use #pragma once, which does the same thing:
#pragma once
(stuff)
(Note there's no #endif at the end of the file.)
It's not in the C++ standard but it's supported by pretty much all of the compilers and is a bit clearer.
In the CreditCardPayment.h file put this:
#ifndef CREDITCARDPAYMENT_H
#define CREDITCARDPAYMENT_H
You must copy your code, it is better to build your class from a tool in your IDE. That will automatically add the header defender for you. And your payment detail function should be virtual.
I'm running into a lot of problems with this, primarily being that my passed Vector of my Class keeps getting flagged as an undeclared identifier. Any help on solving the problem or explanations to help me figure out what I don't understand would be greatly appreciated.
So here is a simplified version of what I have now:
main.cpp
#include "functions.h"
#include "vehicle.h"
int main()
{
int menuSelection;
vector<Vehicle> inventory;
do
{
cout << "Please make a selection:" << endl << endl;
cout << "1: Display Inventory" << endl;
.......
cout << "8 : Write inventory to file and exit" << endl << endl;
if (menuSelection == 1)
{
if (inventory.empty())
cout << "Database empty" << endl;
else
display(inventory);
.......
} while (menuSelection != 8);
return 0;
}
vehicle.h
#pragma once
#include "functions.h"
class Vehicle
{
private:
string VIN;
int year;
.......
// public:
// string getVIN();
.......
}
functions.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void display(vector<Vehicle>);
.......
void display(vector<Vehicle>& in)
{
Vehicle v;
cout << "VIN: " << v.getVIN(in)
}
.......
I've tried a bunch of different things to get it to work so that's why a lot of stuff may seem like odd syntax (I'm also not very good). My assignment is to have a menu in main.cpp which will create a vector from a class stored in vehicle.h, and then the menu is supposed to call functions which are located in functions.h that will communicate through vehicle.h to a fourth not included vehicle.cpp to work with information from the class.
In functions.h, void display(vector<Vehicle>); does not compile because Vehicle is undeclared at this point.
Also, in functions.h, void display(vector<Vehicle>& in) is a different overload to the previous prototype (the & makes a difference), probably not what you intended. And then you place a function body in functions.h -- this should not be there.
You need to organize your code so that Vehicle class definition appears, and then functions.h includes that.
So vehicle.h should look like:
#pragma once
#include <string>
// do NOT include functions.h
class Vehicle
{
// ...
};
and then functions.h should look like:
#pragma once
#include "vehicle.h"
// do NOT do "using namespace std;" in a header and don't include any unnecessary headers
void display(vector<Vehicle> &in);
and then functions.cpp should #include "functions.h" and contain the function body for display.
undeclared identifier means the compiler sees a name but don't see a declaration of that name (as a variable, class, function, etc.). It happens in your code in a few places, for example:
MyClass is used but not declared (main.cpp)
Vehicle is used but not declared (functions.h)
You use Vehicle.v but v not declared in class Vehicle (in addition, I doubt that this is what you intended - if you use class name Vehicle.v it means accessing a static variable, as opposed to vehicle.v).
It seems you lack some basic background. The most important thing is that you learn to decipher compiler errors, so at least you understand what went wrong.
Here is my file.h :
#define MAXCOMPONENTS 20
#include <string>
#include <string.h>
#include <iostream>
class file{
public:
file(char const * filename);
virtual ~file();
void Takeinfocomponents();
void Takeshape();
void Getvalue(int i);
char *Getcomponents();
char *Getcolor();
protected:
private:
char const * filename;
String shape;
int value[MAXCOMPONENTS];
char components[MAXCOMPONENTS];
char color[MAXCOMPONENTS];
};
And my file.cpp :
#include <fstream>
#include <iostream>
#include <string.h>
#include <string>
#include "file.h"
using namespace std;
file::file(char const* filename)
{
cout << "constructor/fichier:" << filename << endl;
ifstream fichier(filename,ios::in);
if(fichier){
this->filename=filename;
fichier.close();
Takeshape();
Takeinfocomponents();
}else{
cout << "File name invalid." << endl;
}
}
file::~file()
{
}
char* file::Getcolor(){
return this->color;
}
char* file::Getcomponents(){
return this->components;
}
void file::Getvalue(int i){
cout << this->value[i] << endl;
}
void file::Takeinfocomponents(){ // pic up name of components, his number and his color
cout << "Takeinfocomponents/fichier:" << filename << endl;
ifstream fichier(this->filename,ios::in);
ifstream stop(this->filename,ios::in);
string line;
int i=0;
getline(fichier,line);
getline(stop,line);
getline(stop,line);
while(line!="/" && i!=99){ // take all informations while the stop signal isn't read
getline(stop,line);
fichier >> this->components[i] >> this->value[i] >> this->color[i];
cout << this->components[i] << this->value[i] << this->color[i] << endl;
i++;
}
fichier.close();
}
void file::Takeshape(){ // pic up the shape in .txt
cout << "Takeshape" << endl;
fstream fichier(this->filename,ios::in);
string shape;
fichier >> shape;
this->shape=shape;
fichier.close();
}
This is a part of a larger programm who make graphic from informations ( from the .txt ), this part is use to pic up informations from the .txt.
The problem come from the declaration of the :
String shape;
He told me that string is not a name type. I've tried with a small "s" :
string shape;
But this ain't working.
I've the impression that i miss a very small things that could unlock my problem.
Thx for help.
Notabene : I'm french and my english is not this good, please answer like i was a little child ahah !
You have to explicitly state the namespace:
std::string shape;
You shouldn't pollute the namespace in the headers, so using namespace std is not an option here.
See also the question about namespace pollution. If you just need strings, prefer to use
using std::string;
in the cpp file.
C++ uses the concept of a namespace. A namespace is used to group types, variables, etc. together in a meaningful way, regardless of the number of header files those types or variables are spread across.
In this example, the string type is inside the std namespace. std is short for Standard Template Library, and it is the namespace that most of C++'s library classes, etc. are stored in.
The correct way of accessing type inside a namespace is namespace::type, so the correct way of accessing the string type inside the std namespace is std::string. You can also write using namespace std to access the types in std without having to write std:: each time, but doing this in a global scope is a bad idea, because it pollutes the global namespace.
In the code you posted, string shape; appears before using namespace std, as the #include "file.h" appears before it. Therefore, it won't take effect.
To be able to use the string class and create string objects, you need to include...
#include <string>
... at the top of your header files.
You do not need...
#include <string.h>
The string class, like all STL classes, is part of the std namespace. If you do not want to write std:: before every class name, you can simply state...
using namespace std;
... at the top of your header files so that instead of...
std::string shape;
... you can simply use...
string shape;