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.
Related
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 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?
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;
I recently finished a course on C++, to test to see what I knew from it I decided to start work on a operating system simulation, it seemed to be going fairly well up till I tried to implement a multiple users system by using a array to store user names, from which the user will select one and it will go into their user. However the problem with it that when I try and modify the array in the header file in the source file the program crashes.
header files:
#ifndef UBUNTU_LOGIN_H
#define UBUNTU_LOGIN_H
#include "Ubuntu_UserDetails.h"
#include <iostream>
#include <string>
#include <vector>
class Ubuntu_Login: protected UserDetails
{
public:
void Ubuntu_UserCreation();
void Ubuntu_login();
};
#endif // UBUNTU_LOGIN_H
#ifndef UBUNTU_USERDETAILS_H
#define UBUNTU_USERDETAILS_H
#include "Ubuntu_login.h"
#include <string>
#include <vector>
class UserDetails
{
protected:
std::string username;
std::string password;
std::string users[0];
};
#endif // UBUNTU_USERDETAILS_H
source files:
#include "Ubuntu_login.h"
#include "Ubuntu_UserDetails.h"
#include <iostream>
#include <vector>
#include <string>
void Ubuntu_Login::Ubuntu_UserCreation()
{
std::cout << "\t _____________" << std::endl;
std::cout << "\t|Create a user|\n" << std::endl;
std::cout << "Enter a username:" << std::endl;
std::getline(std::cin, username);
std::cout << "Enter a password:" << std::endl;
std::getline(std::cin, password);
users[0] = username;
std::cout << users[0] << std::endl;
std::cout << "User created successfully" << std::endl;
}
void Ubuntu_Login::Ubuntu_login()
{
std::cout << "\t ______" << std::endl;
std::cout << "\t|Log in|\n" << std::endl;
std::cout << "Select user" << std::endl;
}
#include "Ubuntu_login.h"
#include <iostream>
int main()
{
Ubuntu_Login UO;
UO.Ubuntu_UserCreation();
UO.Ubuntu_login();
}
when I try to run it I get as far as the initial password entry then the program crashed, I assume this is due to a stack overflow, but I wouldn't know how to solve it. Any help on solving this issue would be greatly appreciated as well as general help on the code as a whole :) .
also the reason I have not included things like storing passwords as hashes or not echoing the password is simply because I don't know the syntax to do it and I wanted to try to do the things I knew how to do first then add additional features later, so don't expect great code :P
Use std::vector<std::string> users
And then just users.push_back(username) to it. Dynamic array is suitable here.
In your Ubuntu_UserDetails.h you have this data member in the UserDetails class:
std::string users[0];
Then in a source file, you have this assignment:
users[0] = username;
If you access an item in an array with index 0, the array must have at least one element. In fact, index 0 refers to the first item in the array.
So, the users array should be defined as having some bigger size.
But, much better, consider using a convenient C++ container class for vectors, like std::vector.
So, in your header file, you can define a data member like this:
// Instead of:
// std::string users[0]
//
std::vector<std::string> userNames; // probably better than "users"
Then you can add new items to the vector using its push_back or emplace_back methods.