when i compile the program i get an error about int when i create a bookClass object using the 2 argument constructor. the error has somerthing to do with the integer argument parsed to the constructor. the program is:
#include <iostream>
#include <string>
using namespace std;
class bookClass{
private:
string bookName;
int bookNumber;
public:
void setName(string c){
bookName=c;
}
void setNumber(int d){
bookNumber=d;
}
string getName(){
return bookName;
}
int getNumber(){
return bookNumber;
}
bookClass(string a, int b){
bookName=a;
bookNumber=b;
}
};
int main()
{
int numberr;
string name;
cout << "Enter the book name: ";
cin >> name;
cout << "\nEnter the book number: ";
cin >> numberr;
bookClass book=new bookClass(name, numberr);
cout << "\n\nThe book " << book.getName() << " has book number " <<
book.getNumber() << endl;
return 0;
}
Compiling your code I didn't get the error you suggested. However, there is an issue with this line:
bookClass book = new bookClass(name, numberr);
C++ is not Java. new returns a pointer to memory dynamically allocated for the given class.
What you want is just:
bookClass book (name, numberr);
The problem with your code is simple. I suppose you were programming in Java or C# before C++. In C++ we call new operator only if we want to create an object explicitely on heap (and get a pointer to it).
bookClass* book=new bookClass(name, numberr);
However, now you are in troubles because you are calling book.getName() where book is of type pointer to something and it has no member getName(). You have to first dereference that pointer and then call a member function (*book).getName(); or simply book->getName();.
However, since C++'s objects do not have to be on the heap (Java objects have to) you can create an object without new operator using bookClass book(name, numberr);
Related
How can I create be object array of type Book in this program.
Tried to create the object but couldnt do it.Its driving me nuts. hence I need a litle help.
#include<iostream>
#include <algorithm>
using namespace std;
class BOOK{
private:
char bookname[20];
float bookprice;
public:
void getBookDetails()
{
cout<<"Enter the Book Name:";
cin>>bookname;
cout<<"Enter the Book Price:";
cin>>bookprice;
}
void displayDetails()
{
cout<<"Book Name:"<<bookname<<endl;
cout<<"Book Price:"<<bookprice<<endl;
}
};
bool comparator(string a, string b)
{
return a<b;
}
int main()
{
int Book=5;
string sortBook[]={"sandwich","apple","banana","zombie","pear"};
std::sort(sortBook,sortBook+Book,comparator);
for(int i=0;i<Book;i++)
{
cout<<sortBook[i]<<" ";
}
}
}
An object array of books would look like this:
int size = 5;
BOOK bookArray[size];
Major Problems
You are not using constructors
You are unnecessarily using char arrays
The string array 'sortBooks' should be a BOOK array (I assume?)
You declared a string array without including the string header file (probably the reason your code won't compile)
In my honest opinion, it seems that you are trying to solve a complex task without first mastering the basics of the language. I would highly recommend watching/reading a complete C++ tutorial, such as The Cherno's C++ Guide or NeuralNine's C++ Guide. Reading TutorialPoint's guides on C++ and The C++ Standard Library would also be helpful. Finally, if I had to recommend something more, I would recommend Sam's Teach Yourself C++, which helps you understand that language on a deeper level and covers many intricacies of the C++ language that beginners often overlook (note: I would not recommend using this book by itself, as it can be dry and difficult at times).
The reason your code isn't doing what you want is because you are not declaring an array of type BOOK, but of type string. Once you change the array to type book, you will run into two main problems:
Declaring an array of objects requires a default constructor.
Comparing classes requires operator overloading
Here is a good reference for learning about constructors. Essentially, a constructor is a special function that shares the exact same name as the class. When the class is declared, the constructor is automatically called. You should use a constructor to initialize the values instead of using the getBookDetails() function. If you used a constructor, you would just be able to write BOOK newBookObject("name", price)
Concerns
You are trying to sort an array of objects, which is difficult because objects are custom types, so the computer doesn't know how to compare two objects with a < (less than sign). Because of this, you would have to manually define how to compare the two objects (via operator overloading).
What You Need To Do:
Include the '<string>' Header File
Add #include <string> to the top of the file.
Change 'char bookname[20]' to 'string bookname'
I would not recommend using char arrays with classes, as it is difficult for a beginner. I agree with this question in that there's no reason to not using a string here, especially when you've already included the string library for the 'sortBooks' array you have at the bottom.
Add a Default Constructor
A default constructor is necessary to declare an array of objects.
BOOK()
{
bookname = ""
bookprice = 0.0
}
Add a Parameterized Constructor
A parameterized constuctor will allow you to declare a BOOK object like this:
BOOK newBook("book name here", price)
An Example:
BOOK newBook("Pride and Prejudice", 50.00)
BOOK(string book_name, double book_price)
{
bookname = book_name;
bookprice = book_price;
}
You can have two methods of the same name, as long as they have different parameters; this is called method overloading
Change the 'sortBooks' array to type BOOK
BOOK bookArray[5] { book1(title, price), book2(title, price) book3(title, price) book4(title, price) book5(title, price) };
Replace 'title' and 'price' with the appropriate titles and prices
Overload the '<' Operator
Comparing by Book Name
bool operator < (BOOK& otherBook)
{
return bookname < otherBook.bookname;
}
Comparing by Price
bool operator < (const BOOK& otherBook)
{
return bookprice < otherBook.bookprice;
}
Just some nitpicks/extra advice:
You don't have to name the data members 'bookname' and 'bookprice'. Since it's already in the context of a class, you could just write 'name' and 'price'.
As a beginner, you should always use doubles instead of floats, since floats have the possibility of introducing rounding errors.
Name classes using PascalCase
Finally, my code
I compiled this code on an Ubuntu Linux Subsystem using G++ (version: 9.3.0)
#include <iostream>
#include <string> //Include the 'string' header
#include <algorithm>
using namespace std;
class BOOK
{
//Private data members
private:
string bookname;
float bookprice;
//Public methods
public:
BOOK()
{
bookname;
bookprice = 0.0;
}
BOOK(string name, double price)
{
bookname = name;
bookprice = price;
}
void getBookDetails()
{
cout << "Enter the Book Name: ";
cin >> bookname;
//Add a 'cout << endl;' here
cout << "Enter the Book Price: ";
cin >> bookprice;
//Add a 'cout << endl;' here
}
void displayDetails()
{
cout << "Book Name: " << bookname << endl;
cout << "Book Price: " << bookprice << endl;
}
bool operator < (BOOK& otherBook)
{
return bookname < otherBook.bookname; //You can access private data members within the same class
}
};
int main()
{
int size = 5;
BOOK bookArray[5]; //an array of 5 'BOOK' objects
if (bookArray[0] < bookArray[1]) //Both have the same value, "" (the default value)
cout << "Item 1 is greater" << endl;
return 0;
}
I am trying to make my program accept pointers as part of a requirement to deallocate the heap space and kill the pointer. My program runs fine without the adjustments I attempted to make to accept pointers. I'm getting the following error
lab.cpp: In function 'int main()':
lab.cpp:21:19: error: request for member 'unit' in 'shipment', which is of pointer type 'cargo*'
(maybe you meant to use '->' ?)
21 | input(shipment.unit);
| ^~~~
lab.cpp:22:20: error: request for member 'unit' in 'shipment', which is of pointer type 'cargo*'
(maybe you meant to use '->' ?)
22 | output(shipment.unit);
| ^~~~
Here is my program without the adjustments, really simple but it works. All it's doing is taking input and outputting it, just setting it up for now as my assignment is to collect data from user and output it while deallocating the heapspace
#include <iostream>
#include <string>
using namespace std;
struct cargo{
string unit;
string unitID;
int airCraft;
int weight;
string destination;
};
void input(cargo shipment){
cout << "Is it a pallet or a container?" << endl;
getline(cin, shipment.unit);
}
void output(cargo shipment){
cout << shipment.unit << endl;
}
int main() {
cargo shipment;
input(shipment);
output(shipment);
return 0;
}
Here is my program with my adjustments
#include <iostream>
#include <string>
using namespace std;
struct cargo{
string unit;
string unitID;
int airCraft;
int weight;
string destination;
};
void input(cargo *shipment){
cout << "Is it a pallet or a container?" << endl;
getline(cin, shipment.unit);
}
void output(cargo *shipment){
cout << shipment.unit << endl;
}
int main() {
cargo *shipment = new cargo;
input(shipment.unit);
output(shipment.unit);
delete shipment;
shipment = nullptr;
return 0;
}
When accessing an pointer's members, you need to use the arrow (->) operator. But your methods input and output takes the cargo pointer. After accessing its member, you'll return the member, not the pointer. So by doing shipment.unit, your returning a string.
To fix it, lest just pass in the pointer.
void input(cargo *shipment){
cout << "Is it a pallet or a container?" << endl;
getline(cin, shipment->unit);
}
void output(cargo *shipment){
cout << shipment->unit << endl;
}
...
input(shipment);
output(shipment);
Additional: After deleting the shipment, assigning it a nullptr is useless. Your not gonna use it anyway.
Can I initiate a string array and pass it as a function that initializes it. I know this sounds redundant, but basically I want to initiate a string array and then pass it to a variable so that I can use it later? Something like this:
This is the .h:
class ScreenBasics{
void setupAnswers(int &_numberOfAnswers, string *_answersText);
string *answersText;
{
This will be the implementation .cpp
void ScreenBasics::setupAnswers(int &_numberOfAnswers, string *_answersText){
answersText = _answersText; // this is where I get confused cause I don't know if I should initiate my string pointer using new like answersText = new string(_numberOfAnswers);
{
so in the main.cpp I can do something like this:
int main( ) {
ScreenBasics basics;
int numberOfAnswers = 4;
string newAnswers [] = { "Good", "Superb", "Great", "Perfect"};
basics.setupAnswers(numberOfAnswers, newAnswers);
// let's say I want to call some of those answers later
for ( int i = 0; i < numberOfAnswers; i++){
cout << basics.answersText[i] << endl;
}
}
Thanks!
Have you thougt about using structs? Both classes and structs can have a mixture of public and private members, can use inheritance, and can have member functions. I would recommend using structs as plain-old-data structures without any class-like features, and using classes as aggregate data structures with private data and member functions.
Your code would look like the following:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
} mine, yours;
int main ()
{
string mystr;
mine.title = "2001 A Space Odyssey";
mine.year = 1968;
cout << "Enter title: ";
getline (cin,yours.title);
cout << "Enter year: ";
getline (cin,mystr);
stringstream(mystr) >> yours.year;
cout << "My favorite movie is:\n ";
printmovie (mine);
cout << "And yours is:\n ";
printmovie (yours);
return 0;
}
void printmovie (movies_t movie)
{
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
Please let me know if you have any questions!
It sounds like your class should use a constructor to initialize the pointer.
class ScreenBasics
{
ScreenBasics(std::string* _answersText, std::size_t size)
: answersText(new std::string[size])
{
// copy values from _answersText to answersText
}
};
Note that since you are allocating a resource dynamically, you will need to implement The Rule of Three: that is, you need to create a copy-constructor, copy-assignment operator and destructor. This is because their default implementations do not semantocally conform to our requirements. For instance, the default copy-constructor and copy-assignment operator perform shallow copies (that is, they copy the pointer but not what it points to). Also, the destructor doesn't free the memory allocated my new[]. You will need to provide your own definition of the destructor that calls delete[].
Fortunately, all this can be avoided by using the standard library container std::vector, which is a dynamic array class that handles the memory allocation for you. The default implementations of the aforementioned constructors will correctly copy/copy-assign a vector if the need be:
class ScreenBasics
{
ScreenBasics(std:vector<std::string> _answersText)
: answersText(_answersText)
{
}
};
Notice that the size also didn't have to be passed as a parameter. A vector maintains its size internally.
Just beginning to learn about structs, I thought I understood how they work, using the dot operator to access a member of an object, but i clearly don't as the readEmployeeRecord function below doesn't work at all. How should i be doing this? (the code is short and self explantory)
Many thanks for taking the time to further explain structs to me! Naturally I tried google first but i couldn't find an example that inputted data quite the way i wanted and wasn't sure how i should be going about it.
#include <iostream>
#include <iomanip>
using namespace std;
//Employee type
struct Employee{
float wage;
char status;
char dept[4]; //for 3letter department, last position is \0 correct?
};
//function definitions
void readEmpoyeeRecord(Employee staff);
void printEmployeeRecord(Employee staff);
int main(){
Employee employeeA;
readEmpoyeeRecord(employeeA);
printEmployeeRecord(employeeA);
return 0;
}
void readEmpoyeeRecord(Employee employee){
cout << "Enter empolyees wage: ";
cin >> employee.wage;
cout << "Enter empolyees status (H or S): ";
cin >> employee.status;
cout << "Enter empolyees dept (ABC): ";
cin >> employee.dept;
}
void printEmployeeRecord(Employee staff){
cout << "Wage: Status: Department:" <<endl;
cout << fixed << setprecision( 2 ) << staff.wage;
}
First, try searching google for "passing parameters by reference and by value".
You'll learn that:
void readEmpoyeeRecord(Employee staff);
passes your variable to the function by value, meaning that a copy of your object is created and used inside the function, so your original object doesn't get modified, but a copy.
To get the desired result, use:
void readEmpoyeeRecord(Employee& staff);
Passing by reference means you pass that exact same object, and not a copy.
Your code will basically work like this:
//create new employee
Employee employeeA;
//call method readEmployeeRecord on a copy of employeeA
readEmpoyeeRecord(employeeA);
//call method printEmployeeRecord on a copy of employeeA
printEmployeeRecord(employeeA);
readEmpoyeeRecord(Employee employee) is copy by value, not reference, so you are loosing your changes.
Use readEmpoyeeRecord(Employee& employee) instead.
Your problem is that in C++, objects are passed by value until you specify otherwise. Thus, in the body of readEmpoyeeRecord you're dealing with a copy of employeeA, not with employeeA itself.
Pass a reference to your readEmpoyeeRecord function. The signature of readEmpoyeeRecord should read:
void readEmpoyeeRecord(Employee &employee)
Currently I'm trying to set up a member function for Student that reads a string from cin, is used as an argument for this function and then creates a Student object with the data. However, is it giving me a bad_alloc error. I know the function is getting the string but it gives this error after the new object is created.
Error:
./a.out
Please insert name for student:
Bob_Russel
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted
Constructor:
Student::Student(string tname){
name = tname;
}
Function:
Student Student::readStudent(istream &i){
Student *stud;
string y;
i >> y;
stud = new Student(y);
return *stud;
}
testStudent.cpp:
#include "Student.h"
int main(){
Student *stud3;
cout << "\nPlease insert name for student:\n";
stud3->readStudent(cin);
return 0;
}
Not only does the code leak memory (creating a new Student in readStudent that is never deleted), in main you are using an uninitialized pointer to call readStudent. Possibly this is corrupting your heap such that the call to new throws a std::bad_alloc.
Take another look at C++ memory management and object lifetimes. There is really no need to use pointers at all here. As a starting point, your main could be modified to this:
int main() {
Student stud3;
std::cout << "Please insert name for student:" << std::endl;
stud3.readStudent(std::cin);
}
It would perhaps also be better if you read in the name within main (as a std::string), and then pass the name directly to the Student constructor:
int main() {
std::cout << "Please insert name for student:" << std::endl;
// Read in the name.
std::string name;
std::cin >> name;
// Create the student with the input name.
Student stud3(name);
}
It looks like you're trying to implement a factory method. If that's the case, then you're missing the static keyword and the correct syntax for the readStudent call.
class Student{
public:
Student(std::string tname);
static Student* readStudent(std::istream &i);
private:
std::string name
};
Student::Student(std::string tname) {
name = tname;
}
Student* Student::readStudent(std::istream &i){
std::string y;
i >> y;
return new Student(y);
}
int main(int argc, char* argv[]){
Student *stud3 = NULL;
std::cout << "\nPlease insert name for student:\n";
stud3 = Student::readStudent(cin);
return 0;
}
You are allocating on the heap using new and never freeing it, thus you run out of memory and get a bad_alloc. For every new there should be a delete.
This will not throw bad_alloc:
Student Student::readStudent(std::istream& i)
{
std::string y;
i >> y;
return Student(y);
}