I'm trying to writing some code for my c++ class. I'm using eclipse. I'm having a hard time trying to understand some of the instructions in the problem.
I've created a base class called Ship and then used inheritance for my CruiseShip class and CargoShip class.
For the CruiseShip class, I'm instructed to create
A print function that overrides the print function in the base class. The CruiseShip
class’s print function should display only the ship’s name and the maximum number
of passengers.
And similarly for the CargoShip class
A print function that overrides the print function in the base class. The CargoShip
class’s print function should display only the ship’s name and the ship’s cargo capacity.
I'm not sure what it means to "override" the print function in the base class.
It also instructs me to
Demonstrate the classes in a program that has an array of Ship pointers. The array
elements should be initialized with the addresses of dynamically allocated Ship ,
CruiseShip , and CargoShip objects. The program should then step through the array, calling
each object’s print function.
#include <iostream>
#include <string>
using namespace std;
class Ship
{
protected:
string ship_name;
int year_built;
public:
Ship()
{
ship_name="";
year_built=0;
}
void set_ship_name(string str)
{
ship_name=str;
}
void set_year(int y)
{
year_built=y;
}
int get_year()
{
return year_built;
}
string get_ship_name()
{
return ship_name;
}
void print(string, int)
{
cout<<"Ship name is "<<ship_name<<" and it was built in the year "<<year_built<<endl;
}
};
class CruiseShip: public Ship
{
private:
int max_passengers;
public:
CruiseShip()// :Ship(str,year)
{
max_passengers=0;
}
void set_passengers(int pass)
{
max_passengers=pass;
}
int get_passengers()
{
return max_passengers;
}
void print1(string, int)
{
cout<<"Ship name is "<<get_ship_name()<<" and max number of passengers are "<<max_passengers<<endl;
}
};
class CargoShip: public Ship
{
private:
int cargo_capacity_in_tons;
public:
CargoShip()//:Ship (str,year)
{
cargo_capacity_in_tons=0;
}
void set_capacity(int pass)
{
cargo_capacity_in_tons=pass;
}
int get_capacity()
{
return cargo_capacity_in_tons;
}
void print2(string, int)
{
cout<<"Ship name is "<<get_ship_name()<<" and its capacity is "<<cargo_capacity_in_tons<<" Tons."<<endl;
}
};
int main(){
CruiseShip ship1;
CargoShip ship2;
string ship_name1;
string ship_name2;
int year_built1;
int year_built2;
int max_passengers;
int cargo_capacity_in_tons;
cout<<"What is the name of the cruise ship?"<<endl;
cin>>ship_name1;
ship1.set_ship_name(ship_name1);
cout<<"What year was "<<ship_name1<<" built in?"<<endl;
cin>>year_built1;
ship1.set_year(year_built1);
cout<<"What is the maximum capacity of "<<ship_name1<<"?"<<endl;
cin>>max_passengers;
ship1.set_passengers(max_passengers);
//ship1.print(ship_name1, year_built1);
ship1.print1(ship_name1, max_passengers);
cout<<"What is the name of the cargo ship?"<<endl;
cin>>ship_name2;
ship2.set_ship_name(ship_name2);
cout<<"What year was "<<ship_name2<<" built in?"<<endl;
cin>>year_built2;
ship2.set_year(year_built2);
cout<<"What is the maximum capacity of "<<ship_name2<<" in tons?"<<endl;
cin>>cargo_capacity_in_tons;
ship2.set_capacity(cargo_capacity_in_tons);
ship2.print2(ship_name2, cargo_capacity_in_tons);
return 0;
}
Let´s say you have the following classes:
class Animal
{
private:
int x;
int y;
public:
virtual string sound() {return "Animal";}
void move() {x += 1; y+=1;}
};
class Cow
{
string sound() {return "Muh"} //this is overriding
string sound(string soundYouWant) {return soundYouWant;} //this is not overriding as string sound(string soundYouWant) is not the same as string sound()
void move() {x += 1; y+=1;} //this is also not overriding as move() in Animal has no virtual
};
So to summarize, overriding means you have a virtual method in the base class and you re-declare it in the derived class. This way, you are able to re-define it for every derived class (the method-body can be different for the base class and each of its derived classes).
Now to dynamic allocated arrays:
int size;
std::cin >> size;
int *array = new int[size]; //the array is stored on the heap
delete[] array; //deallocates the array and so frees the memory
If you create an array on the stack (without new), you either have to hardcode its size using literals (0, 1, 2, ...) or using a const int variableName. This way, the compiler knows the array size during compile time. So you have to know the array size while writing your program. Consequently, the compiler wouldn´t allow you to do this: std::cin >> size;.
Using new (dynamical arrays) you are allowed to specify the array size during compile time. So it is legal to let your program calculate the array size or take it as an user input. With dynamic arrays you also have a lot, lot, lot more memory than using the small stack (stackoverflow).
int *array: obviously the memory content is interpreted as integers. *array points to the first element of the array. int *array does NOT know the SIZE of the array. You have to keep track of that yourself.
new int[size]: You are reserving space for size * integers on the heap.
You might know that C++ does not have a garbage collector. This is when delete[] array; comes into play. When you don´t need array anymore (this includes other pointers pointing to array) you should call delete to free the memory. With small, short running programs, forgetting it won´t matter as the OS (operation system) will free the memory after your program has terminated. Nevertheless, you should use delete as not using it is very bad still and will lead to trouble with bigger programs. You should place delete in the destructor of a class (~clasname()) if you use array within a class.
Related
I want to allocate new memory for my class which has some derived classes as well. as I have defined a constructor of type Professor(string name,int age,int publications,int cur_id) memory allocation
per[i] = new Professor; in the main throws error:no matching function for call to 'Professor::Professor().
another error I am getting is candidate: 'Professor::Professor(std::string, int, int, int) expects 4 arguments, 0 provided. please help me how to define a constructor which allocates memory without giving any error, thanks.
ps: I am trying to solve this question
part of my class looks like;
class Person{
protected:
string name;
int age;
public:
Person(string name,int age){
name=name;
age=age;
}
int z=0;
void getdata(){
string m;int n;
cin>>m>>n;
z++;
Person(m,n);
}
void putdata(){
cout<<name<<" "<<age<<endl;
}
};
class Professor: public Person{
public:
int publications;
int cur_id;
Professor(string name,int age,int publications,int cur_id)
:Person(name,age)
{
publications=publications;
cur_id=cur_id;
}
int b=0;
void getdata(){
string a;int b,c;
cin>>a>>b>>c;
b++;
Professor(a,b,c,b);
}
void putdata(){
cout<<name<<" "<<age<<" "<<publications<<" "<<cur_id<<endl;
}
};
class Student:public Person{
public:
int marks[6];
int cur_id;
Student(string name,int age,int arr[6],int cur_id)
:Person(name,age)
{
marks[6]=arr[6];
cur_id=cur_id;
}
int s=0;
void getdata(){
string p;int q;int r[6];
cin>>p>>q;
for(int i=0;i<6;i++){
cin>>r[i];
}
s++;
Student(p,q,r,s);
}
void putdata(){
cout<<name<<" "<<age<<" "<<marks[0]<<" "<<marks[1]<<" "<<marks[2]<<" "<<marks[3]<<" "<<marks[4]<<" "<<marks[5]<<" "<<cur_id<<endl;
}
};
My main function looks like
int main(){
int n, val;
cin>>n; //The number of objects that is going to be created.
Person *per[n];
for(int i = 0;i < n;i++){
cin>>val;
if(val == 1){
// If val is 1 current object is of type Professor
per[i] = new Professor;
}
else per[i] = new Student; // Else the current object is of type Student
per[i]->getdata(); // Get the data from the user.
}
for(int i=0;i<n;i++)
per[i]->putdata(); // Print the required output for each object.
return 0;
}
Your problem has nothing to do with dynamic allocations. You are trying to construct Professors and Students by calling their default constuctor (new Professor / new Student), but they don not have a default constructor.
A default constructor is a constructor that can be called without parameters. You can change existing constructors:
Person(string name = "",int age = 42) : name(name), age(age) {}
And similar for Student. Note that your constructor implementation was wrong. You assigned the parameters to themself but did not initialize the members. The member initialization list is a special place where you can use the same name for member and argument without shadowing.
Alternatively call the constructor with parameters.
Glad to see you are trying to improve your C++ skills. However, there are few things you can do to improve the code quality and style:
per[i]->getdata(); // Get the data from the user. will not work.
You have not defined getdata() with a virtual prefix.
Mark the overloaded methods in your child classes with an override suffix.
The same problem exists for putdata()
Virtual destructor is missing.
Is it valid to create a Person object? I think not. Therefore:
Constructor can be protected.
Person::getdata() can be a pure virtual function.
Person::z is a public member variable.
Member variables in child classes (Student and Professor) are also public.
Mentioned already by #463035818_is_not_a_number that Person *per[n]; is not portable C++.
As suggested by #JulienLopez, generally avoid raw pointers in C++11 and above. Use std::shared_ptr or std::unique_ptr.
I think you're missing the point of a constructor a bit here.
The idea is to have all the data ready to create your instance before hand, and then instanciate your class (either Professor or Student).
So your constructors are good, but you getdata member functions are not.
The easiest way would be for your getdata functions to become free functions (or static member functions, in our case, it's pretty much the same), and they gather the datas needed for construction and instanciate your class. (and a clearer name wouldn't hurt while we're at it)
Professor* createProfessorFromCin()
{
string a;int b,c;
cin>>a>>b>>c;
return new Professor(a,b,c,b+1);
}
and your calling code would just end up as
per[i] = createProfessorFromCin();
for example.
Also, few tips if you plan on improving this piece of code:
use smart pointers, it's not the 90's anymore, your code well be a lot more memory
safe (on the same vein, std::vector or std::array would be nice for the grades too)
If you plan on adding more subclasses of the sort, you should look into the Factory pattern for more OCP-friendly code.
Your Person class needs a virtual destructor (once you will fix your memory issues), otherwise your instances won't get destroyed properly.
So basically, I want my first class to be a basic one, just like in the example down below, to be inherited, and the child classes which come out of it, to have a same named function, that will return the fictional price of something, but I don't know how to access the functions while writing a void function out of classes, which recieves an array of pointers of the basic class and then the number of array elements, then calls for the same named function in both child classes.
Take a look yourself.
While you're at it, feel free to tell me any errors I've made along the way, regards!
#include <iostream>
#include <cstring>
#include <ctype.h>
using namespace std;
class basic{
protected:
char name[20];
public:
basic(char * n)
{
strcpy(name,n);
}
};
class advanced1:public basic{
protected:
float price;
public:
advanced1(char * n, float p):basic(n)
{
price=p;
}
float priced()
{
if(price<10)
return price*1.5;
else
return price*1.2;
}
};
class advanced2:public basic{
protected:
float price;
public:
advanced2(char * n, float p):basic(n)
{
price=p;
}
float priced()
{
if(price<15)
return price*2.3;
else
return price*1.8;
}
};
void printstuff(basic *basics[], int basicsN)
{
for(int i=0;i<basicsN;i++)
{
cout<<basics[i]->priced();
}
}
What you are describing is a "virtual" function. You can follow this tutorial.
Looking at your code, it seems like you don't actually want the base class to implement the function. For that you'd have to use a pure virtual function - see this link. But keep in mind that using a pure virtual function means that you cannot directly instantiate the base class.
And about errors, just on first glance, the way you use strcpy could write beyond the end of the name array. I recommend using strncpy (see this) instead and specifying the number of characters. If you want to copy exactly 20 characters always, you could specify 20, or if 20 is just the limit, you could use strlen to get the length of the incoming string and then copy std::min(20, length) characters.
I made hospital class and patient class, so what I am trying to do is to make Patient[] patients < this. However, there is showing some error error: expected unqualified-id before '[' token
I do not know what it is wrong with that.
Thank you for your response.
class Hospital
{
public:
Hospital();
void determinePatientType();
protected:
private:
Patient[] patients;
char * fileName;
int patientCapacity;
char * hospitalName;
int totalPatients;
};
1- That is not how to declare an array:
Patient[] patients;
You must make the subscript operator after the identifier not before it.
Patient patients[size];
2- You have to specify array size at compile time so:
patient pat[size];
The size must be constant at compile time. If you want a dynamic size then consider using dynamic arrays. Also i recommend using class vector.
To use a dynamic array you should use pointesrs:
patient* patients;
And layer on you can allocate it:
patients = new patient[size];
Your class could look like:
nclude
using namespace std;
class Hospital{
public:
Hospital(int); // constructor
~Hospital(); // destructor
Hospital();
void determinePatientType();
private:
Patient* patients;
char * fileName;
int patientCapacity;
char * hospitalName;
int totalPatients;
};
Hospital::Hospital(int size){
patients = new Patient[size]; // allocating dynamic memory
// some initialization and processing here
}
Hospital::~Hospital(){
delete[] patients; //freeing up memory
}
I have 1 question because I am pretty curious how to handle with such problem.
I have base class called "Pracownik" (Worker) and 2 subclasses which are made from public Pracownik;
- Informatyk (Informatic)
- Księgowy (Accountant)
Writing classes is easy. Made them pretty fast but I have small problem with main because I am helping friend with program but I was not using C++ for a while. So:
This is my header file "funkcje.h"
#include <iostream>
using namespace std;
class Pracownik
{
private:
string nazwisko;
int pensja;
public:
Pracownik(string="",int=0);
~Pracownik();
string getNazwisko();
int getPensja();
friend double srednia_pensja(int,Pracownik);
};
class Informatyk : public Pracownik
{
private:
string certyfikat_Cisco;
string certyfikat_Microsoft;
public:
Informatyk(string="",int=0, string="", string="");
~Informatyk();
void info();
};
class Ksiegowy : public Pracownik
{
private:
bool audytor;
public:
Ksiegowy(string="",int=0, bool=false);
~Ksiegowy();
void info();
};
double srednia_pensja(int,Pracownik);
These are definitions of my functions "funkcje.cpp"
#include "funkcje.h"
Pracownik::Pracownik(string a,int b)
{
nazwisko=a;
pensja=b;
}
Pracownik::~Pracownik()
{
}
string Pracownik::getNazwisko()
{
return nazwisko;
}
int Pracownik::getPensja()
{
return pensja;
}
Informatyk::Informatyk(string a, int b, string c, string d) : Pracownik(a,b)
{
certyfikat_Cisco=c;
certyfikat_Microsoft=d;
}
Informatyk::~Informatyk()
{
}
Ksiegowy::Ksiegowy(string a, int b, bool c) : Pracownik(a,b)
{
audytor=c;
}
Ksiegowy::~Ksiegowy()
{
}
void Informatyk::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Certyfikat Cisco: "<<certyfikat_Cisco<<endl;
cout<<"Certyfikat Microsoft: "<<certyfikat_Microsoft<<endl;
}
void Ksiegowy::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Audytor: ";
if(audytor)
cout<<"Tak"<<endl;
else
cout<<"Nie"<<endl;
}
double srednia_pensja(int a,Pracownik *b)
{
return 0;
}
And finally main!
#include <iostream>
#include "funkcje.h"
using namespace std;
int main()
{
Pracownik lista[10];
Pracownik *lista_wsk = new Pracownik[10];
Informatyk a("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk b("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk c("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy d("Kowalski4",4000,1);
Ksiegowy e("Kowalski5",5000,0);
lista[0]=a;
lista[1]=b;
lista[2]=c;
lista[3]=d;
lista[4]=e;
Informatyk *ab = new Informatyk("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk *ac = new Informatyk("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk *ad = new Informatyk("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy *ae = new Ksiegowy("Kowalski4",3000,1);
Ksiegowy *af = new Ksiegowy("Kowalski5",3000,0);
lista_wsk[0]=*ab;
lista_wsk[1]=*ac;
lista_wsk[2]=*ad;
lista_wsk[3]=*ae;
lista_wsk[4]=*af;
for(int i;i<5;i++)
{
lista[i].info();
cout<<endl;
}
cout<<endl;
// for(int i;i<5;i++)
// {
// lista_wsk[i].info();
// }
return 0;
}
Ok and here goes my questions:
I had to create array which is filled with base class objects "Pracownik".
Secondary i had to create array which is full of pointers to class "Pracownik" objects.
(Hope those 2 first steps are done correctly)
Next thing I had to write to array 3 objects of class Informatic and 2 of class Accountant.
So I ve created 5 objects manually and added them into the array in such way array[0]=a;. I guess this is still good.
Next thing i had to create and add similar objects to array of pointers using new. So I ve created array with new and pointers to objects with new. (Hope thats correct 2).
And FINALLY:
I had to use info() on added to array objects.
This is my main question if my array is type "Pracownik" and I want to use function info() from subclasses how should I do that? And how compiler will know if he should use info() from Accountant or Informatic while I am trying to show those information using "for".
In an array of Pracownik, the elements are of type Pracownik. Any information about the objects being of a subclass of Pracownik are lost when you copy the elements into the array.
This is called object slicing and leads to the fact that there is no way to invoke Informatyk::info() on these objects.
If you want to call methods of a subclass, you have to prevent object slicing by storing pointers or references in the array.
As Oswald says in his answer,
Pracownik * lista_wsk = new Pracownik[10];
allocates an array of 10 Pracownik objects. This is probably not what you want. With polymorphism involved, we usually want to deal with pointers or references. Hence, you'd want an array of Pracownik * pointers. Since you already know at compile-time that it will have 10 members, there is no need for a dynamic allocation here. I think you've meant to write
Pracownik * lista_wsk[10];
instead. Now we don't put objects but pointers to objects into the array. For example:
lista_wsk[2] = new Informatyk("Kowalski3", 3000, "Cisco3", "Microsoft3");
And then we can iterate over the items like so:
for (unsigned i = 0; i < 10; ++i)
std::cout << lista_wsk[i]->getNazwisko() << std::endl;
As you have already discovered, it is impossible to call a subclass function member on a superclass object. It would be possible to figure out the actual type at run-time yourslf by means of a cast.
for (unsigned i = 0; i < 10; ++i)
if (Informatyk * info_ptr = dynamic_cast<Informatyk *>(lista_wsk[i]))
info_ptr->info();
dynamic_cast returns a pointer to the target class if this is possible or a nullptr (which evaluates to false, hence the conditional) otherwise. Note however that this is considered very poor style. It is better to use virtual functions. Therefore, add
virtual void
info()
{
// Do what is appropriate to do for a plain Pracownik.
// Maybe leave this function empty.
}
to the superclass and again to the subclass
virtual void
info() // override
{
// Do what is appropriate to do for an Informatyk.
}
The function in the subclass with the same signature is said to override the function inherited from the superclass. Since the function is marked as virtual, the compiler will generate additional code to figure out at run-time what version of the function to call.
If you are coding C++11, you can make the override explicit by placing the keyword override after its type as shown above (uncomment the override). I recommend you use this to avoid bugs that arise from accidental misspelling or other typos.
I'm trying to make a chess program, but I want to be able to implement different AIs in it. Thus I made a abstract AIgeneric class and the derived class AIrandom off of AIgeneric. Then in my chessAI interface, I create a list of the the AIs, and try to call their getNextMove function and run into a segfault. The code is as below:
class AIgeneric {
public:
virtual int getNextMove(int*, const int &) = 0;
}
class AIrandom : public AIgeneric {
public:
AIrandom();
virtual int getNextMove(int*, const int &);
}
class chessAI {
public:
chessAI();
~chessAI();
void setAI();
int getNextMove(int*, const int &);
private:
vector<AIgeneric*> AIlist;
vector<string> names;
int selectedAI;
};
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
int chessAI::getNextMove(int * board, const int & color) {
return AIlist[selectedAI]->getNextMove(board, color); //segfault on this line
}
It'd be great if anyone could help me on this problem!
Edit: I do set selectedAI to 0 before calling getNextMove.
In this code:
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
You store a pointer to a local variable into your vector. After the constructor returns that pointer is no longer valid.
Remember that all local variables are stored on the stack, and the stack is reused in other functions. So when you use the pointer in the vector, it now points to some other functions memory and not the one object you declared.
This can be solved in three ways:
Allocate the object on the heap:
AIlist.push_back(new AIRandom);
Not using pointers at all.
Use smart pointers, such as std::unique_ptr.
You call selectedAI = -1; and then AIlist[selectedAI]->.... What do you expect AIlist[-1] to be, other than undefined behavior?
I expect this is because AIlist[selectedAI] is out of bounds. You can confirm this by replacing it with AIlist.at(selectedAI). Keep in mind that this index is -1 immediately after the constructor...