Issues with classes and static variables - c++

I am having troubles wrapping my head around the use of static class variables, and what exactly to include within the main file, as opposed to the function file. When I try to compile my code I get a huge number of errors.
The question provided requires me to create a static ID variable that is incremented by each new animal (e.g. Elephant and Cheetah), so elephant would display ID 1 and cheetah ID 2. I know my animal.h file is correctly formatted, but I am unsure about the main and animal.cpp files.
Could someone please correct any issues that are present within my code? Thanks!
animal.h
#include <iostream>
#include <string>
using namespace std;
#ifndef ANIMAL_H
#define ANIMAL_H
class animal{
public:
animal();
animal(string aSpecies); //Animals are allocated a unique ID on
//creation,
//the first animal has ID 1, second is 2
//and so on
void set_name(string aName); //Change the animals name
string get_species();
string get_name();
std::string name;
std::string species;
int get_ID(); //The animals unique ID
static int currentID; //The next ID number to give out
~animal();
};
#endif //ANIMAL_H
animal.cpp
#include <iostream>
#include "animal.h"
using namespace std;
//static ID variable
int animal::currentID = 0 ;
//Default animal constructor implementation
animal::animal(){
name = "?";
currentID++;
}
animal::animal(string aSpecies){
species = aSpecies;
}
void animal::set_name(string aName){
name = aName;
}
std::string animal::get_species(){
return species;
}
std::string animal::get_name(){
return name;
}
main-1-1.cpp
#include <iostream>
#include "animal.h"
using namespace std;
int main(){
animal Elephant;
animal Cheetah;
Elephant.set_name("Katrina");
Cheetah.set_name("Alex");
cout << Elephant.get_name() << " " << animal::currentID <<endl;
cout << Cheetah.get_name() << " " << animal::currentID << endl;
return 0;
};

There is some syntax to correct
The static member variable has the classes namespace, so in main you also have to call it with
animal::currentID
Then, new returns a pointer, so Elephant and Cheetah should be declared like
animal* Elephant;
animal* Cheetah;
Elephant = new animal("Elephant");
Cheetah = new animal("Cheetah");
However, there is no reason to use pointers here, just do
animal Elephant("Elephant");
animal Cheetah("Cheetah");
Also, the default constructor has not been defined in the classes body, you have to add
animal();
to the class declaration.
The members name and species are missing in the class body, too so make sure to add
private:
std::string name, species;
to the class body
There is no << operator for animal yet, so the output does not know what to do. You can add them to the class or output only the species member of the animal. Overloading the operator would look like this
std::ostream& operator<<(std::ostream &os, animal const &A){
os << "The animal " << A.name << " is of species " << A.species
<< " and has ID " << A.myID;
};
And you typically declare it as a friend non-member, so add
friend std::ostream& operator<<(std::ostream &os, animal const &A);
to the class body, this allows the operator to access the private members of animal. Note that this requires <iostream> for animal to work. You can then do
std::cout << Cheetah << std::endl;
And it will print the description of Cheetah.
Some further advice:
Having using namespace in a header file is a dangerous thing, it might bring things into scope that you are not aware of.
From the code you posted, currentID has no reason to be a member of animal, it can just be a local variable in main. If you want to keep track automatically, you can add a non-static member myID and increment the ID upon construction like this
class animal{
public:
animal::animal():myID(++currentID){};
private:
static int currentID;
int myID`
};
int animal::currentID = 0;

It looks like you are declaring the static variable correctly and setting it to zero. However, you need to increment it in the constructors (animal::animal).
The other issue is that you are using the new keyword to allocate two animals on the heap, but then you are assigning the pointers to animal objects. Here are two ways you could handle this instead instead:
animal Elephant("Elephant"); // Not on the heap
OR
animal *Elephant = new animal("Elephant"); // Elephant is a pointer to an object on the heap
Another thing, std::cout has no way of knowing how to print these objects. Instead of printing them directly, you should call one of your get_ functions:
cout << "The animal " << Elephant.get_species() << ... ;
Finally, if you want to be able to access the ids of the animals, you need to store the ids as member variables and use the static id variable as an incremented to ensure that every animal has a unique, consecutive id.

Related

Cin and cout in a constructor

I'm told to read a name from a constructor (homework), however the class constructor is not supposed to take any parameters - something I find weird.
I have tried to simply put cout's and cin.getline's inside the constructor, butt that doesn't work. I don't get how I can read data from user inside a constructor that does not have any parameters. Is it even possible?
E.g
class Animal
{
private:
char name[20];
public:
Animal() { SOMEHOW READ NAME HERE WITHOUT CON. PARAMETER }
};
int main() {
Animal a1; // should ask for name and read it, add it to data
return 0;
}
#include <iostream>
#include <sstream>
class Animal
{
public:
Animal() : name()
{
// Not the best design approach.Just show it possible for the question.
std::cout << "Name of animal?" << std::endl;
std::getline(std::cin, name);
std::cout << name << std::endl;
}
private:
std::string name;
};
int main(int argc, char * argv[])
{
Animal a1; // should ask for name and read it, add it to data
return 0;
}
I believe the code below is self explanatory with comments to guide you. In object oriented, a class should contain setter and getter methods. I have created a class Animal with one private string variable name. In the constructor, I ask for a name and assign it to the name variable of the object which is being created. I then display the name using a method called getName() which returns the current object's name and it is also known as a getter method. I believe you are new to Object Oriented and I hope I have made these concepts understandable to you.
#include <iostream>
using namespace std;
class Animal
{
private:string name;
public: Animal() {
cout<<"Enter the animal's name?";
getline(cin,this->name); //sets the current obj's name (storing the value)
cout<<"The animal's name is "<<getName();
}
public: string getName(){ return this->name; } //return current obj's name value (getter method)
};
int main()
{
Animal a1;
//cout<<a1.getName(); //it will get the name of a1's object
return 0;
}
#include <iostream>
using namespace std; //Don't kill me
class animal
{
private:
char name [20];
public:
animal () //Constructor without parameters
{
cout<<"Please enter animal name: ";
cin>>name;
}
void getAnimal();
};
void animal :: getAnimal()
{
cout<<name;
}
int main ()
{
animal a1;
a1.getAnimal();
}
Remember that there are 3 types of constructors. In this case it seems that you have to use a default constructor which does require a parameter as it is just setting name to a default value. To get a user defined value you can use cin within the constructor. When you create an object in main and run your program it will allow the user to enter a name.
To read and print the name I found that a getter method was easier.
https://www.geeksforgeeks.org/constructors-c/

map of derived classes

I have a base class
class Person{
public:
Person(string name , int age ){
this -> name = name;
this -> age = age;
}
virtual void getInfo(){
cout << "Person " << name << " " << age;
}
void add(string name , const Person & b){
a[name] = b
}
protected:
string name;
int age;
map<string , Person > a;
};
That contains map of object type Person. I want to push various derived classes into that map e.g
Derived class
class Kid : public Person{
public:
Kid(string name, int age):Person(name,age){};
virtual void getInfo( ){
cout << "Kid " << name << " " << age;
}
};
I want add method of Person class to bahave such as
Person one("John",25);
one.add("Suzie",15);
Which fails. I know i can remake the code using pointers e.g
map<string , Person*> a
void add( string name , Person *b){
a[name] = b;
}
Person one("John",25);
one.add(new Kid("Suzie",15))
But is there a way how to achieve it without using pointers?
No, you can't obtain polymorphism without using references or pointers.
The issue is easily understood by thinking that a non pointer object requires to store the whole class data (including the vtable).
This means that a map<string, person> will store somewhere person instances in a sizeof(person) slot.
But a sizeof(person) can't contain enough data to store additional information of subclasses of person. This leads to object slicing.
your original design ends up recursing infinitely. You need a polymorphic map, but do you need it to be a member of the class??
Take a look at this question Can a c++ class include itself as an attribute?

How to pass "&player" object into another inherited class constructor ("score")?

I am new to C++ and I am creating a small program to understand more about inheritance in programming languages.
From what I gather, inheritance is when you have the authority and permission to obtain all member functions and values of the parent/base class. An analogy in real life would be inheriting some of my father's physical properties like eye colour etc (although I wish I could inherit his business mind...)
Anyways, one thing I am trying to do is to try and pass an already initialized object into an inherited class constructor.
This is my code so far:
#include <string>
#include <iostream>
using namespace std;
class player{
private:
string name;
int level;
public:
player(const string &n, const int &l) : name(n), level(l){};
string getName() const {return name;}
int getLevel() const {return level;}
};
class score: public player{
private:
int scores;
public:
score(const int &s, const string &n, const int &l) : player(n, l), scores(s){};
void setScore(int newScores){scores = newScores;}
int getScore() const {return scores;}
};
int main(){
player steve("steve", 69);
cout << steve.getName() << endl;
cout << steve.getLevel() << endl;
}
Basically, I want to pass the object that I have intialised in my main() program function steve by reference into a constructor in the score class. However, I don't know how to do this? Would it be something like score(const player &p, const int &s) : player(&p), scores(s)?? I get how to pass like member values, but I am interested in passing in objects themselves?
Would mean a lot if someone could assist me here, as I really like programming especially C++
You can't extend an object of a base class (player) to an object of a child class (score) because this would require to allocate more memory space directly after the original object to store the additional elements of the child class.
In your example, you can define this constructor to copy values from the player object for a new score object:
score(const player &p, const int &s) : player(p.n, p.l), scores(s){};
If you just want to link the player object, then the score class must include a pointer to this object.

C++ Friendship / Polymorphic Classes Error

In C++, I am using polymorphic classes and friendship to make a basic 'friends group'. However, when I am trying to access the private age function of the class person, which is a friend of the class Boy, I cannot access it. What is the problem?
/* Polymorphic Classes and Class Friendship */
#include <iostream>
class Person{
public:
Person(char* name, int age) : Name(name), Age(age){}
char* Name;
virtual void Speak(void){
std::cout << "I am a person called " << Name << std::endl;
}
virtual ~Person(void){delete this;}
private:
int Age;
};
class Boy : public Person{
friend class Person;
public:
Boy(char* name, int age, Person* Friend) : Person(name, age), MyFriend(Friend){}
void Speak(void){
std::cout << "I am a boy called " << Name << ". My friend " << MyFriend->Name << "'s age is " << MyFriend->Age /* Error here */ << std::endl;
}
~Boy(void){delete this;}
private:
Person* MyFriend;
};
int main(void){
Person* John = new Person("John", 12);
Boy* James = new Boy("James", 14, John);
Boy* Keith = new Boy("Keith", 18, James);
John->Speak();
James->Speak();
John->~Person();
James->~Boy();
Keith->~Boy();
return (0);
}
technical problem:
c++ friendship is one-way.
try protected to give access to derived classes.
code review:
/* Polymorphic Classes and Class Friendship */
It's a good idea to avoid C /*…*/ multiline comments in C++, because they do not nest, and some/many programmers use them to comment out code for debugging.
Instead preferentially use C++ // (single-) line comments.
#include <iostream>
OK.
class Person{
public:
OK.
Person(char* name, int age) : Name(name), Age(age){}
The first argument should be char const*. Without the const you will, for example, not be able to pass a literal string, when using a C++11-conforming compiler.
char* Name;
The raw pointer here needs to match the constructor formal argument.
Effectively, the way that it's initialized as a simple copy of the constructor's pointer argument, it limits the lifetime of any Person instance to the lifetime of the actual argument.
A std::string is a far more flexible and unproblematic choice.
virtual void Speak(void){
std::cout << "I am a person called " << Name << std::endl;
}
Since this function is not const, it cannot be called on a const object.
Also, the void is C-ism, ungood in C++.
In C it says that this function does not take any arguments. In C++ that's unnecessary, i.e. that void is needless verbiage. Besides, C doesn't even have member functions.
virtual ~Person(void){delete this;}
Again, the void is ungood.
The delete this is extremely ungood in this context.
private:
int Age;
The only problem with this is failure to apply some naming convention for data members. For example, like age_ (note that the underscore then goes at the end), or like my_age or myAge.
};
OK.
class Boy : public Person{
OK.
friend class Person;
Meaningless, since class Person doesn't access anything from this class.
public:
Boy(char* name, int age, Person* Friend) : Person(name, age), MyFriend(Friend){}
Again, should be char const*. Or std::string const&.
void Speak(void){
std::cout << "I am a boy called " << Name << ". My friend " << MyFriend->Name << "'s age is " << MyFriend->Age /* Error here */ << std::endl;
}
Here, if the compiler supports it, do add an override in order to have the compiler check that you're really overriding a base class function, like void Speak() override {.
In other words, ditch the void which is needless C-ism verbiage, but do add the override, which is very useful.
~Boy(void){delete this;}
The void is ungood.
The delete this is extremely ungood in this context.
private:
Person* MyFriend;
As earlier, this again limits the lifetime of a Boy instance.
};
OK.
int main(void){
The void is ungood.
Person* John = new Person("John", 12);
Boy* James = new Boy("James", 14, John);
Boy* Keith = new Boy("Keith", 18, James);
John->Speak();
James->Speak();
John->~Person();
So far OK.
James->~Boy();
Keith->~Boy();
Don't ever call destructors explicitly. Well, a really good experienced programmer might do that when using placement new for allocation: it is in the language for a reason. But as a beginner, and even with a year or two professional experience, don't do that.
return (0);
Technically OK but unecessary. main returns 0 by default.
}
You have specified that Person is a friend to Boy, but you want Boy to be friend of Person. However there's no need to use friendship. Boy already inherits Person thus if you declare age as protected class Boy can see it.

Using base class function with derived class values

I'm having problems getting a vector of objects to print the name of the derived class rather then the base class.
These are my classes
#include <vector>
#include <iostream>
using namespace std;
class Object
{
string name;
public:
string getName()
{
return name;
}
};
class Flashlight : public Object
{
string name = "Flashlight";
public:
string getName();
};
This is my main, it has a vector of the objects and at this point just needs to print out their names.
int main()
{
vector<Object> items;
items.push_back(*new Flashlight);
for(int i = 0; i < items.size(); i++)
{
cout << i+1 << " " << items.at(i).getName();
}
}
Right now if I assign something to the name in Object it will print that but its not using the derived classes values, I just want it to inherit the function then use its own values with it. I've tried implementing the function in the base classes(but seeing as I could have a lot of those in future it would lead to lots of redundant code) but that doesn't work either.
Instead of declaring variable 'name' in derived classes, initialize the variables value as custom value for that derived class. Also I would suggest you to make getName method as virtual. You also do not need to override getName method in derived classes if you just want to output name.
Try this way:
int main()
{
vector<Object *> items;
items.push_back(new Flashlight);
for(int i = 0; i < items.size(); i++)
{
cout << i+1 << " " << items.at(i)->getName();
}
}
Also as mentioned in another answer it would be good to use virtual methods read about it here.
What is more you need to use constructor to set value for variable name. You can read about them here
You should try this way:
class Object
{
private:
string name;
public:
Object() : name("Object")
{}
Object(string str) : name(str)
{}
string getName()
{
return name;
}
};
class Flashlight : public Object
{
public:
Flashlight() : Object("Flashlight")
{}
string getName();
};
Your code has two problems:
getName() is not virtual. This means that the actual function called is decided at compile time, based on the variable static type. So, if your variable is of type Object, Object& or Object* (or any const variation on those), function Object::getName() will be called, regardless of the actual type of the object referred to or pointed to by your variable (the dynamic type).
You have a vector<Object>, which means that all objects stored in it are of type Object. You can try to put a Flashlight object in it, but only the Object part will be copied into the vector. If you need polymorphism in a vector<>, you need a vector of pointers (or even better, smart pointers).
So you have to do two things to get the desired behaviour:
Declare function getName() as virtual string getName() (even
better, virtual const string& getName() const)
Declare items as vector<Object*> items (even better, use an
appropriate smart pointer such as unique_ptr<> instead of a raw
pointer)