Constructor with string (using char array) parameter - c++

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);
}
};

Related

How can i access to any data that is in private section of class?

#include <iostream>
#include <vector>
using namespace std;
class Test
{
private:
int ID;
string name;
public:
Test(int ID, string name);
};
Test::Test(int ID, string name)
{
this->ID = ID;
this->name = name;
}
int main()
{
vector<Test *> test_vect;
Test *ptr = new Test(100, "John");
test_vect.push_back(ptr);
cout << ptr->ID << endl;
return 0;
}
This is a simple code I'm trying.
I want to access to the data that I stored in vector.
I thought it would be accessible by using -> just like vector of struct but I can't. So I want to know how to load the data in class.
In addition, I thought sending data to heap section using new would make it accessible at any time I want regardless of whether it is private or public, but it seems like it is not possible.
Can you explain how it works?
(I don't even fully understand how class work, so detailed explanation would be very appreciated. Thx!)
A private variable cannot be accessed by code outside the class definition. (There are exceptions with friend)
ptr->ID does not work because main is outside the class definition.
This can be fixed by using a getter method.
#include <iostream>
#include <vector>
using namespace std;
class Test
{
private:
int _ID;
string _name;
public:
int ID() {return _ID;}
string name() {return _name;}
Test(int param_ID, string param_name);
};
Test::Test(int param_ID, string param_name)
{
_ID = param_ID;
_name = param_name;
}
int main()
{
vector<Test *> test_vect;
Test *ptr = new Test(100, "John");
test_vect.push_back(ptr);
cout << ptr->ID() << endl;
return 0;
}
The above example shows the getter methods ID() and name() which return the data members _ID and _name respectively.
ID() is allowed to access _ID because ID() is part of the class definition. name() is allowed to access _name because name() is part of the class definition.
Note: I would still consider this code to be flawed because it creates a new object on the heap, but does not delete it. You should also look up the keywords new and delete to see how they operate together.

Problem constructing a base class from within a subclass constructor

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...

C String assigning values in explicit constructor in C++?

I have a class BankAccount with two string members - name and num. What I want is to assign values to these objects when I create them (when the constructor is called). However the compiler says No instance of constructor matches the argument list when I try to create an object.
I would like to ask why is that?
// hwk-2.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include "pch.h"
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
class BankAccout {
char name[23];
char num[15];
double sum;
public:
BankAccout(char *nm, char *nr, double s) {
strcpy(name,nm);
strcpy(num, nr);
sum = s;
}
};
int main()
{
BankAccout k("Peter", "0403940940", 34.21);
}
as a coffee break exercise here is more idiomatic version
#include "pch.h"
#include <iostream>
#include <string>
class BankAccount {
std::string name_;
std::string num_;
double sum_;
public:
BankAccount(std::string name, std::string num, double sum) {
name_ = name;
num_ = num;
sum_ = sum;
}
};
int main()
{
BankAccount k("Peter", "0403940940", 34.21);
}
The signature of the constructor does not match.
This one will match:
BankAccount(const char *nm, const char *nr, double s);
EDIT:
The reason is the way you are calling the constructor in the main function. You are giving literal strings as parameters. These literals are const, you cannot change them at runtime. Thus you will pass pointers to const char*.
This is very obvious if you look at this opposing example. This is a way that would be compatible with the old signature BankAccout(char *nm, char *nr, double s);.
int main(int argc, char* argv[])
{
char name[] = "hello";
char number[] = "1234";
std::cout << "name before: " << name << std::endl;
BankAccount k(name, number, 8.5);
// name and number are not const,
// you can change them :
name[2] = 'x';
name[3] = 'x';
std::cout << "name after: " << name << std::endl;
return 0;
}
An even simpler version, if you don’t need to have additional functionality in the class: just use a struct.
#include <string>
struct BankAccount {
std::string name;
std::string number;
double balance;
};
int main() {
BankAccount account{"Joy", "44", 43.};
}

How can I initialize char arrays in a constructor?

I'm having trouble declaring and initializing a char array. It always displays random characters. I created a smaller bit of code to show what I'm trying in my larger program:
class test
{
private:
char name[40];
int x;
public:
test();
void display()
{
std::cout<<name<<std::endl;
std::cin>>x;
}
};
test::test()
{
char name [] = "Standard";
}
int main()
{ test *test1 = new test;
test1->display();
}
And sorry if my formatting is bad, I can barely figure out this website let alone how to fix my code :(
If there are no particular reasons to not use std::string, do use std::string.
But if you really need to initialize that character array member, then:
#include <assert.h>
#include <iostream>
#include <string.h>
using namespace std;
class test
{
private:
char name[40];
int x;
public:
test();
void display() const
{
std::cout<<name<<std::endl;
}
};
test::test()
{
static char const nameData[] = "Standard";
assert( strlen( nameData ) < sizeof( name ) );
strcpy( name, nameData );
}
int main()
{
test().display();
}
Your constructor is not setting the member variable name, it's declaring a local variable. Once the local variable goes out of scope at the end of the constructor, it disappears. Meanwhile the member variable still isn't initialized and is filled with random garbage.
If you're going to use old-fashioned character arrays you'll also need to use an old-fashioned function like strcpy to copy into the member variable. If all you want to do is set it to an empty string you can initialize it with name[0] = 0.
Since you are using C++, I suggest using strings instead of char arrays. Otherwise you'd need to employ strcpy (or friends).
Also, you forgot to delete the test1 instance.
#include <iostream>
#include <string>
class test
{
private:
std::string name;
int x;
public:
test();
void display()
{
std::cout<<name<<std::endl;
}
};
test::test()
{
name = "Standard";
}
int main()
{
test test1;
test1.display();
std::cin>>x;
}
Considering you tagged the question as C++, you should use std::string:
#include <string>
class test
{
private:
std::string name;
int x;
public:
test();
void display()
{
std::cout<<name<<std::endl;
std::cin>>x;
}
};
test::test() : name("Standard")
{
}
c++11 actually provides two ways of doing this. You can default the member on it's declaration line or you can use the constructor initialization list.
Example of declaration line initialization:
class test1 {
char name[40] = "Standard";
public:
void display() { cout << name << endl; }
};
Example of constructor initialization:
class test2 {
char name[40];
public:
test2() : name("Standard") {};
void display() { cout << name << endl; }
};
You can see a live example of both of these here: http://ideone.com/zC8We9
My personal preference is to use the declaration line initialization because:
Where no other variables must be constructed this allows the generated default constructor to be used
Where multiple constructors are required this allows the variable to be initialized in only one place rather than in all the constructor initialization lists
Having said all this, using a char[] may be considered damaging as the generated default assignment operator, and copy/move constructors won't work. This can be solved by:
Making the member const
Using a char* (this won't work if the member will hold anything but a literal string)
In the general case std::string should be preferred

exc_bad_access error

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.