I'm writing a program for a homework assignment. The program compiles and runs, but has a bad access error.
This is main.cpp
#include <iostream>
#include <string>
#include "Mammal.h"
#include "Dog.h"
#include "Horse.h"
#include "Pig.h"
#include "Cat.h"
using namespace std;
//Seed for ease of grading
const int SEED=100;
const int NUM_ANIMALS=5;
const int WEIGHT_LIMIT=150;
void MammalAssignment(const Mammal * new_Mammal, int choice, string newName);
void UserChoice(const Mammal * new_Mammal);
void ListAnimal(const Mammal *new_Mammal);
int main()
{
string newName, newWeight;
srand(SEED);
Mammal *new_Mammal[NUM_ANIMALS];
UserChoice(*new_Mammal);
for(int i=0; i<NUM_ANIMALS; i++)
ListAnimal(new_Mammal[i]);
//Program pauses for user input to continue
char exit_char;
cout<<"\nPress any key and <enter> to exit\n";
cin>>exit_char;
return 0;
}
void UserChoice(const Mammal * new_Mammal)
{
int choice;
bool choiceGood;
string newName;
for(int i=0;i<NUM_ANIMALS; i++){
choiceGood=false;
while(choiceGood==false)
{
cout<<"-Please choose a number 1-4 for the corresponding animal-\n"
<<"1-Dog\n2-Horse\n3-Pig\n4-Cat\n";
cin>>choice; //User choice
if(choice<=0 || choice >=5){
cout<<"Your choice is invalid\n\n";
continue;
}
choiceGood=true;
} //While loop
cout<<"\nPlease enter a name for the animal you have chosen(Ex. Fido).\n";
cin>>newName;
MammalAssignment(&new_Mammal[i], choice, newName);
} //For loop
}
void MammalAssignment(const Mammal * new_Mammal, int choice, string newName)
{
if(choice==1){
Dog newDog(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newDog;
}
else if(choice==2){
Horse newHorse(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newHorse;
}
else if(choice==3){
Pig newPig(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newPig;
}
else if(choice==4){
Cat newCat(rand()%(WEIGHT_LIMIT+1), newName);
new_Mammal=&newCat;
}
}
void ListAnimal(const Mammal *new_Mammal)
{
cout<<"-------------------------\nName:"
<<new_Mammal->GetName()<<"\nWeight: "
<<new_Mammal->GetWeight();
}
Mammal.h
#ifndef MAMMAL_H
#define MAMMAL_H
using namespace std;
class Mammal
{
public:
Mammal(); //Default constructor
Mammal( int newWeight); //Parameterized constructor
void SetWeight(int newWeight);
virtual string GetName() const;
int GetWeight() const;
//virtual function to be defined by derived animal classes
virtual void Speak() const;
private:
int weight;
};
#endif
Mammal.cpp
#include <iostream>
#include <string>
#include "Mammal.h"
using namespace std;
Mammal::Mammal()
{
SetWeight(0);
cout<<"\nInvoking default Mammal Constructor\n";
}
Mammal::Mammal( int newWeight)
{
SetWeight(newWeight);
cout<<"\nInvoking parameterized Mammal Constructor\n";
}
void Mammal::SetWeight(int newWeight)
{
weight=newWeight;
}
int Mammal::GetWeight() const
{
return weight;
}
string Mammal::GetName() const
{}
void Mammal::Speak() const
{
cout<<"\nLadies and gentlemen, the mammal speaks...\n";
}
Dog.h
#ifndef DOG_H
#define DOG_H
#include "Mammal.h"
using namespace std;
class Dog: public Mammal
{
public:
Dog(); //Default constructor
Dog(const int& newWeight,const string& newName); //Parameterized constructor
void SetName(string newName);
string GetName() const;
//mammal virtual function
virtual void Speak() const;
private:
string name;
};
#endif
Dog.cpp
#include <iostream>
#include <string>
#include "Dog.h"
using namespace std;
//Default constructor
Dog::Dog()
{
cout<<"\nInvoking default Dog constructor\n";
}
//Parameterized constructor
Dog::Dog( const int& newWeight,const string& newName):Mammal(newWeight)
{
SetName(newName);
cout<<"\nInvoking parameterized Dog constructor.\n";
}
void Dog::SetName(string newName)
{
name=newName;
}
string Dog::GetName() const
{
return name;
}
//mammal virtual function
void Dog::Speak() const
{
Mammal::Speak();
cout<<"\nWoof!\n";
}
The other derived classes(horse, pig, and cat) are all identical to Dog. I'm getting a Exc_Bad_Access error when ListAnimals() gets to GetWeight(). As far as I can tell it's returning the right file type. Any help would be awesome
Your MammalAssignment function is returning a pointer to a local variable. Once the function returns, that memory (which was on the stack) is gone and you will crash when you access it as an object of the relevant mammal type.
You need to return a pointer to memory allocated using operator new, or possibly just an object instead of a pointer, assuming suitable copy semantics are implemented in your Mammal classes.
A revision (or initial self-education?)of memory management in C++ would be in order before you go any further. See also smart pointers, to avoid new/delete where possible and make your life easier.
Mammal *new_Mammal[NUM_ANIMALS];
You need to allocate memory using new !
Mammal *new_Mammal = new Mammal[NUM_ANIMALS];
Also I think your UserChoice function should take the pointer as a reference and not as a const value to be able to change the actual content.
Related
I need to get in a vector the names of some cities as soon as they are created... In order to accomplish that I created a static vector for the class City, however when I try to compile my code I get the error
error: lvalue required as unary '&' operand
this->cities.push_back(&this);
^~~~
What am I doing wrong?
My code is the following...
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
class City
{
private:
string name;
static vector<City *> cities;
public:
string getName() { return name; }
City(string name) : name{name}
{
this->cities.push_back(&this);
};
~City(){};
} hongKong{"Hong Kong"}, bangkok{"Bangkok"}, macau{"Macau"}, singapura{"Singapura"}, londres{"Londres"}, paris{"Paris"}, dubai{"Dubai"}, delhi{"Delhi"}, istambul{"Istambul"}, kuala{"Kuala"}, lumpur{"Lumpur"}, novaIorque{"Nova Iorque"}, antalya{"Antalya"}, mumbai{"Mumbai"}, shenzen{"Shenzen"}, phuket{"Phuket"};
int main()
{
}
this is already a City* pointer, so drop the & from &this.
Also, don't forget to actually define the static vector object.
Also, you should account for the class' copy/move constructors and destructor, to make sure you don't miss adding pointers, or leave behind dangling pointers.
Try this:
#include <iostream>
#include <ctime>
#include <vector>
using namespace std;
class City
{
private:
string name;
static vector<City *> cities;
public:
string getName() { return name; }
City(string name) : name{name}
{
cities.push_back(this);
}
City(const City &src) : name{src.name}
{
cities.push_back(this);
}
City(City &&src) : name{std::move(src.name)}
{
cities.push_back(this);
}
~City()
{
cities.erase(std::find(cities.begin(), cities.end(), this));
}
};
vector<City *> City::cities;
City hongKong{"Hong Kong"}, bangkok{"Bangkok"}, macau{"Macau"}, singapura{"Singapura"}, londres{"Londres"}, paris{"Paris"}, dubai{"Dubai"}, delhi{"Delhi"}, istambul{"Istambul"}, kuala{"Kuala"}, lumpur{"Lumpur"}, novaIorque{"Nova Iorque"}, antalya{"Antalya"}, mumbai{"Mumbai"}, shenzen{"Shenzen"}, phuket{"Phuket"};
int main()
{
}
I have 2 classes. Since Doctor will be considered as Employee, I should be using Employee class functions in Doctor class. Only extra thing that Doctor class has is TITLE. Basically, What I tried is I wanted to send value to Doctor's constructor,set title then send remained value to Employee's class ;however, I could not. This is what I have done so far,
employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class Employee {
private:
int ID;
char *firstname;
char *lastname;
int telno;
char *adress;
char *mail;
int salary;
public:
Employee();
Employee(int,char *,char*,int,char*,char*,int);
char* getfmame();
char* getlname();
char* getadress();
char* getmail();
int getID();
int gettel();
int getsalary();
void printall();
};
#endif
Employee.cpp
#include <iostream>
#include "employee.h"
using namespace std;
Employee::Employee() {
firstname = "Empty";
ID=0;
firstname="Empty";
lastname="Empty";
telno=0;
adress="Empty";
mail="Empty";
salary=0;
}
Employee::Employee(int id,char * first,char* last,int tell,char* adres,char* email,int salar){
ID=id;
firstname=first;
lastname=last;
telno=tell;
adress=adres;
mail=email;
salary=salar;
}
char* Employee::getfmame(){ return firstname; }
char* Employee::getlname(){ return lastname; }
char* Employee::getadress(){ return adress; }
char* Employee::getmail(){ return mail; }
int Employee::getID(){ return ID; }
int Employee::gettel(){ return telno; }
int Employee::getsalary(){ return salary; }
void Employee::printall(){
cout<<endl<<"EMLOYEE INFORMATION"<<endl<<"------------------"<<endl;
cout<<endl<<"ID :"<<ID<<endl<<"FIRST NAME: "<< firstname <<endl<<"LAST NAME: "<< lastname << endl << "TELEPHONE NUMBER: "<<telno<<endl<<"ADRESS: "<<adress<<endl<<"MAIL: "<<mail<<endl<<"SALARY: "<<salary<<endl;
}
Doctor.h
#ifndef DOCTOR_H
#define DOCTOR_H
#include "Employee.h"
using namespace std;
class Doctor :Employee {
public:
enum title {Intern=0,Practitioner=1,Assistant=2,Specialist=3,Docent=4,Professor=5,None=6};
Doctor();
Doctor(title a,int id,char * first,char* last,int tell,char* adres,char* email,int salar);
};
#endif
Doctor.cpp
#include <iostream>
#include "Doctor.h"
#include "Employee.h"
using namespace std;
Doctor::Doctor() {
title tit = None ;
}
Doctor::Doctor(title a,int id,char * first,char* last,int tell,char* adres,char* email,int salar) {
title tit=a;
Employee(id,first,last, tell,adres,email,salar);
printall();
cout<<"typed";
}
Main.cpp
#include <iostream>
#include "employee.h"
#include "doctor.h"
using namespace std;
int main(){
Doctor a=Doctor(Doctor::None,12,"a","b",0550550505,"8424 str nu:5","#hotmail",5000);
return 0;
}
Subclass construction in C++ works so that the base class object must be constructed when the subclass' constructor body is executed:
class A {
/* etc. etc. */
public:
void do_stuff();
};
class B : public A {
B() {
// at this point, an A has already been constructed!
A::do_stuff();
}
};
Note that in this example, since we haven't chosen an explicit constructor for the A instance, the default constructor, A::A(), will be used; and if that constructor is unavailable - we get a compilation error. The fact that a constructor for A has been called is what allows us to then use methods of class A - like A::do_stuff() in the example above.
But - how can we specify a different constructor before the body of the B constructor? Or in your case, how can we use the appropriate constructor for Employee before the body of the Doctor constructor?
The answer was suggested by #user4581301: You need to use an member initializer list. Initializations/constructions on this list are performed before the body, and may include the underlying class. I'll demonstrate with a simplified example. Let's suppose an Employee only has an id and a Doctor only has an additional title.
class Employee {
protected:
int id_;
public:
Employee(int id) : id_(id) { };
int id() const { return id_; }
};
class Doctor : public Employee {
protected:
std::string title_;
public:
Doctor(int id, std::string title) : Employee(id), title_(title) { };
const std::string& title() const { return title_; }
};
So, when a Doctor is being constructed, it constructs its underlying Employee instance using the id it got. The constructor body is used for more complex code beyond simple member initializations.
PS:
You might want to initialize the title_ member with std::move(title) rather than just title, see this question for details.
It's confusing when a constructor has more than two or three parameters with compatible types - users are likely to confuse them with each other. You might consider default values for most fields and setting them after construction, or alternatively, using a builder pattern.
address, with two d's, not adress.
Unless you plan on editing char* fields in-place, use const char *.
They way you've written your classes, Doctor methods would not have write acesss to Employee methods; make sure that's what you intended.
I have some other nitpicks but I'll stop now...
Just to make everyone aware. I have to use char array for strings, this is homework and has to be done that way. Also the classes are made on purporse.
I'm supposed to read a fish' name via my Fish class, which is a subclass of Animal class. If the input length is more than 0, then I'll run the constructor with the char array parameter and update the "fishname" inside Fish class. If not, I'll run the constructor without parameter (Fish() constructor).
My questions:
Right now it gives me the option to write in an input, I do that - it crashes. It is the Fish object causing it, but don't know why. How come?
How would I transport the data that I'll get into "fishname" in the Fish data, over to "name" in the Animal class?
So this is what I have made so far, but it only crashes after input.
#include
using namespace std;
#include <iostream>
using namespace std;
class Animal {
private:
char* name;
public:
Animal() { strcpy(name, ""); } // Constructors that set name to nothing
void writeName() { cout << name; } // Function to read an animal's name
};
class Fish : public Animal {
private:
char* fishname;
public:
Fish() {}
Fish(const char* name) { strcpy(fishname, name); }
};
int main() {
char fishname[20];
cout << "Read fish's name: "; cin.ignore();
cin.getline(fishname, 20);
if(strlen(fishname) > 0) Fish f1(fishname);
else Fish f1;
return 0;
}
About the best you can do, short of implementing a lot of the functionality of std::string is to use a fixed size char array. This is not generally a good practice. I would not usually do this, but I will take pity.
#include <iostream>
#include <cassert>
using namespace std; // NEVER write this in a header file. Just saying.
class Animal {
public:
static const int max_name = 128;
Animal() {
name[0] = 0;
}
void writeName() { cout << name; } // Function to read an animal's name
private:
char name[max_name];
};
class Fish : public Animal {
private:
char fishname[Animal::max_name];
public:
Fish() {
fishname[0] = 0;
}
Fish(const char* name) {
assert(strlen(name) < Animal::max_name);
strcpy(fishname, name);
}
};
Based on my Snack.cpp, Snack header file, MiniVend header file & miniVend.cpp file, I am trying to move my Snack private member - price into my MiniVend.cpp file to generate the amount * price to return a total value of items in my machine. How do I access the price from another class?
Portion of my miniVend.cpp file
double miniVend::valueOfSnacks()
{
return //// I don't know how to get snacks price in here? I need to access snacks & getSnackPrice.
}
miniVend header
#ifndef MINIVEND
#define MINIVEND
#include <string>
#include "VendSlot.h"
#include "Snack.h"
using std::string;
class miniVend
{
public:
miniVend(VendSlot, VendSlot, VendSlot, VendSlot, double); //constructor
int numEmptySlots();
double valueOfSnacks();
//void buySnack(int);
double getMoney();
~miniVend(); //desructor
private:
VendSlot vendslot1; //declare all the vending slots.
VendSlot vendslot2; //declare all the vending slots.
VendSlot vendslot3; //declare all the vending slots.
VendSlot vendslot4; //declare all the vending slots.
double moneyInMachine; //money in the machine
};
#endif // !MINIVEND
Snack.cpp
#include "Snack.h"
#include <iostream>
#include <string>
using std::endl;
using std::string;
using std::cout;
using std::cin;
Snack::Snack() //default constructor
{
nameOfSnack = "bottled water";
snackPrice = 1.75;
numOfCalories = 0;
}
Snack::Snack(string name, double price, int cals)
{
nameOfSnack = name;
snackPrice = price;
numOfCalories = cals;
}
Snack::~Snack()
{
}
string Snack::getNameOfSnack()
{
return nameOfSnack;
}
double Snack::getSnackPrice()
{
return snackPrice;
}
int Snack::getNumOfCalories()
{
return numOfCalories;
}
Snack.h file
#ifndef SNACK_CPP
#define SNACK_CPP
#include <string>
using std::string;
class Snack
{
private:
string nameOfSnack;
double snackPrice;
int numOfCalories;
public:
Snack(); //default constructor
Snack(string name, double price, int cals); //overload constructor
~Snack(); //destructor
//Accessor functions
string getNameOfSnack(); //returns name of snack
double getSnackPrice(); //returns the price of the snack
int getNumOfCalories(); //returns number of calories of snack
};
#endif // !SNACK_CPP
Assuming getSnackPrice() is public, and Snack.h does exist, you should just be able to call
snackObject.getSnackPrice() * ammount
what you need is friend keyword. Define the
friend class className;
I don't really understand why you don't just implement get()? Accessing private data is really bad. You are breaking the encapsulation. But if you really want to know (i.e. you should NOT do it, it is really BAD), then you just return a reference to a private data as shown below
#include <iostream>
class A
{
public:
A(int a) : x(a) {}
int &getPrivateDataBAD() { return x; }
void print() { std::cout << x << std::endl; }
private:
int x;
};
class B
{
public:
void print(int &s) { std::cout << s << std::endl; }
};
int main()
{
A obj(2);
B bObj;
bObj.print( obj.getPrivateDataBAD() );
return 0;
}
my program basically depends on setters to initialize the data in my object instances but I want to remove them and have constructors in place of the setters, Is there a way I can do this or can anybody provide me a reference?
Instantiate object
//Using SDL and standard IO
#include <SDL.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <iomanip>
#include <archer.hpp>
#include <ctime>
#include <ArmouredArcher.hpp>
#include <RNGI.hpp>
using namespace std; //Declaring use of namespace std
void instantiateMuskateer();
int main(int argc, char* argv[])
{
//init muskateer object
instantiateMuskateer();
system("pause");
return 0;
}
Instantiation, Activity and destruction
void instantiateMuskateer()
{
Archer* Muskateer = new Archer();
Muskateer->setName("Brett");
delete Muskateer;
}
.hpp file
#ifndef _Archer_
#define _Archer_
#include <string>
class Archer
{
public:
inline Archer() :
name(""),
healthpoints(0),
baseDamage(0),
range(0)
{ ; } //All Member varials are in a known state
inline Archer(std::string name, int healthpoints, int baseDamage, int range) :
name(name),
healthpoints(healthpoints),
baseDamage(baseDamage),
range(range) //All member variables are in a known state
{
;
}
inline ~Archer() { ; } // empty destructor
inline std::string getName() { return name; }
inline void setName(std::string name) { this->name = name; }
inline int getHealthPoints() { return healthpoints; }
inline void setHealthPoints(int healthpoints) { this->healthpoints = healthpoints; }
inline int getBaseDamage() { return baseDamage; }
inline void setBaseDamage(int baseDamage) { this->baseDamage = baseDamage; }
inline int getRange() { return range; }
inline void setRange(int range) { this->range = range; }
/*std::string getName(); //getter for name
void setName(std::string name); //Set the name
int getHealthPoints();
void setHealthPoints(int healthpoints);
int getBaseDamage();
void setBaseDamage(int baseDamage);
int getRange();
void setRange(int range); */
protected:
private:
// copy constructor
Archer(const Archer& other) = delete;
// overload assignment operator
Archer& operator=(const Archer& other) = delete;
std::string name;
int healthpoints;
int baseDamage;
int range;
};
#endif
In your example, it is really simple, you just have to take the parameters you need in your constructor:
Archer(std::string n) :
name(n),
healthpoints(0),
baseDamage(0),
range(0)
{} //All Member varials are in a known state
And then you can simply do that:
void instantiateMuskateer()
{
Archer* Muskateer = new Archer("Brett");
delete Muskateer;
}
A few comments not related, but to improve your code. Writing inline is useless when you declare and implement your functions inside your class, the inline is implied. Also, if your destructor does nothing, you should not define it or use = default, that way you can enable some optimizations from the compiler.
Also, in your previous function i see no need to allocate the object on the heap, it is again a loss of performance and a source of error (such as forgetting to delete the object), allocate it on the stack:
void instantiateMuskateer()
{
Archer Muskateer("Brett");
// do your things
}
Or use a unique_ptr.