C++ Inheritance and Pointer Errors (Beginner) - c++

I'm a relative beginner to C++, I've been learning for the past 4 months. We have an an assignment to do for school; create a text based adventure game using what we have learnt so far from C++. We went over classes, inheritance and pointers today so I thought that I'd get some practice using classes/inheritance.
My code so far is:
Character.h (The header file)
#ifndef CHARACTER_H
#define CHARACTER_H
#include <cstdlib>
class Character
{
private:
int Health;
public:
Character();
~Character();
int GetHealth() {return Health;}
void SetHealth(int newHealth) {Health = newHealth;}
};
class Monster:public Character
{
int GetHealth() {return Health;}
void SetHealth(int newHealth) {Health = rand()% 50+100;}
}
#endif
Character.cpp
#include "Character.h"
Character::Character()
{
Health = 100;
}
Character::~Character()
{
}
Battle.cpp (Where everything takes place)
#include <iostream>
#include <cstdlib>
#include "Character.h"
using namespace std;
int main()
{
Character* Player = new Character();
Monster* Monster1 = new Monster();
cout << "Player's Health is: " << Player->SetHealth << endl << endl;
cout << "Monster's Health is: " << Monster1->SetHealth << endl << endl;
}
Let me explain what I'm trying to do...
I'm simply trying to get the program to display the health of both the player and the monster.
In the character header file, the class 'Character' is a base for every character in the game. Then I Get and Set the health for the class. Then I'm trying to create a child class called 'Monster' derived from the 'Character' class. This will have different health compared to the standard character class but I'm not sure how to do that. I wanted to make the health randomly generate between 50 and 100. Then in the 'Battle.cpp' file I am trying to create a new character called 'Player' which includes the default amount of health (which is 100) and a new monster called 'Monster1'. Then I want to display the health for both characters. I also aim to create multiple monsters with varying amounts of health.
When I try to run the program I seem to get a large amount of errors saying 'See declaration of Character::Health'.
I'm not too sure what I've done wrong as I'm still fairly new to C++ and still trying to get my head around the concepts of pointers and inheritance.

Let me answer inside the code:
#ifndef CHARACTER_H
#define CHARACTER_H
#include <cstdlib>
class Character
{
// this property will be used in the derived classes, we need protected instead of private
protected:
int Health;
public:
Character();
~Character();
// This method is to be repeated in the derived class, and publicly accessible
// (not only inside the class, but also outside (like you do in main())
public:
int GetHealth() {return Health;}
// This method needs to be redefined in Monster, that's a candidate for a virtual method
virtual void SetHealth(int newHealth) {Health = newHealth;}
};
class Monster:public Character
{
// You don't need this anymore - the GetHealth from class Character is accessible
// int GetHealth() {return Health;}
// you override a method - write a different version. Use virtual to note that
virtual void SetHealth(int newHealth) {Health = rand()% 50+100;}
}; // lacked a semi-colon here :)
#endif
And the code for Battle.cpp
#include <iostream>
#include <cstdlib>
#include "Character.h"
using namespace std;
int main()
{
Character* Player = new Character();
Monster* Monster1 = new Monster();
// The moment you cout, you need to provide a value (a method that returns something).
// You want to "GetHealth()" in order to show it :)
cout << "Player's Health is: " << Player->GetHealth() << endl << endl;
cout << "Monster's Health is: " << Monster1->GetHealth() << endl << endl;
}
I also don't like what you do with Health in the class. First you declare it private - so nobody can change it in an unauthorized way. Then you declare a plain SetHelth() which lets you do anything with the value.
Instead you could make a initial value in the constructor:
#ifndef CHARACTER_H
#define CHARACTER_H
#include <cstdlib>
class Character
{
// this property will be used in the derived classes, we need protected instead of private
protected:
int Health;
public:
Character();
~Character();
// This method is to be repeated in the derived class, and publicly accessible
// (not only inside the class, but also outside (like you do in main())
public:
int GetHealth() {return Health;}
};
class Monster:public Character
{
// You don't need this anymore - the GetHealth from class Character is accessible
// int GetHealth() {return Health;}
public:
Monster();
}; // lacked a semi-colon here :)
#endif
And the Character.cpp
#include "Character.h"
Character::Character()
{
Health = 100;
}
Character::~Character()
{
}
Monster::Monster()
{
Health = rand()% 50+100;
}
And then you can change it with methods like DrinkHealthPotion(); or GetDamage();

I think your problem might be a typo, where you have written:
cout << "Player's Health is: " << Player->SetHealth << endl << endl;
cout << "Monster's Health is: " << Monster1->SetHealth << endl << endl;
I believe you mean GetHealth and not SetHealth, also GetHealth is a function so you will have to call it with parenthesis GetHealth().
So I believe that you want it to say:
cout << "Player's Health is: " << Player->GetHealth() << endl << endl;
cout << "Monster's Health is: " << Monster1->GetHealth() << endl << endl;
Hope that helps, and good luck with your future endeavors with C++

Related

Subclass member variable as argument for main-class constructor in initialization list = crash?

Very new to programming so forgive me for maybe not seeing something obvious.
Basically I just want to know why all three codes do compile, but the resulting executables CRASH in cases TWO and THREE
(I marked the differences with comments)
ONE - compiles
#include <iostream>
#include <string>
using namespace std;
string testrace = "dog"; //defining it only globally
class Attributes {
public:
Attributes (string race){
if (race == "human"){
intelligence = 10;}
else if (race == "dog"){
intelligence = 4;}
}
int intelligence;
};
class Dalmatian: public Attributes{
public:
// but NOT locally
Dalmatian (): Attributes{testrace} { //using it as an argument
cout << "do i even arrive here" << endl;
}
};
int main() {
Dalmatian bob;
cout << bob.intelligence << endl;
}
TWO - crashes
#include <iostream>
#include <string>
using namespace std;
class Attributes {
public:
Attributes (string race){
if (race == "human"){
intelligence = 10;}
else if (race == "dog"){
intelligence = 4;}
}
int intelligence;
};
class Dalmatian: public Attributes{
public:
string testrace = "dog"; //only defining it locally
Dalmatian (): Attributes{testrace} { //using it as argument
cout << "do i even arrive here" << endl;
}
};
int main() {
Dalmatian bob;
cout << bob.intelligence << endl;
}
THREE - crashes
#include <iostream>
#include <string>
using namespace std;
string testrace = "dog"; //defining it globally
class Attributes {
public:
Attributes (string race){
if (race == "human"){
intelligence = 10;}
else if (race == "dog"){
intelligence = 4;}
}
int intelligence;
};
class Dalmatian: public Attributes{
public:
string testrace = "dog"; // AND locally
Dalmatian (): Attributes{testrace} { //using it as argument
cout << "do i even arrive here" << endl;
}
};
int main() {
Dalmatian bob;
cout << bob.intelligence << endl;
}
What I am looking for, of course, is a working alternative to example TWO.
However I am also interested in an explanation why all of the three pieces of code will compile fine, but executables resulting from 2 and 3 will crash.
EDIT: I do know that examples ONE and THREE don't make sense, I used them for demonstrational purposes. (Also fixed my wording, compiler did fine, executable crashed);
EDIT2: I do, of course, realize that I could just replace "testrace" with ""dog"", but for easier transferability to other subclasses, I would prefer a solution that lets me use a variable argument for Attributes(), that I can vary depending on the subclass, that is invoking the main class.
First off when you have
...
string testrace = "dog";
Dalmatian (): Attributes{testrace}
...
testrace will hide the global testrace as class members supersede global variables when you are in class scope. This means both example two and three use the same variable, the class member variable.
The reason two and three crash because you are trying to use a variable that has no been constructed before. When you get to
Dalmatian (): Attributes{testrace}
testrace has not yet been constructed. Even though you have string testrace = "dog"; in the class body that initialization doesn't happen until after Attributes{testrace} is called. So Attributes (string race) gets a uninitialized string and using it is undefined behavior and also causes your crash.
The problem is that at the time that Attributes is constructed the testrace variable is yet uninitialized, and accessing it gives you undefined behavior.
You can simply fix this by writing
Dalmatian (): Attributes{"dog"} { //using it as argument
cout << "do i even arrive here" << endl;
}
See the working code here.

const int Employee::number is protected

A little weird prob;em i came across when working on something that I got stuck with and I have no idea why this happens.
So i have 2 files (actually way more but those arent important) called Employee and Keeper. Employee is the base class while Keeper is the derived class.
The employee has several attributes and a method called saveFile and the keep inherits these.
Employee.h:
protected:
const int number;
const std::string name;
int age;
// All ordinary employees
Employee *boss = nullptr; // works for ...
public:
void saveFile(std::ostream&) const;
Keeper.cc
void Keeper::saveFile(ostream& out) const
{
out << "3\t3\t"
<< number << "\t" << name << "\t" << age
// The error happen here on boss->number
<< "\t" << cage->getKind() << "\t" << boss->number << endl;
}
Keeper.h (full code)
#ifndef UNTITLED1_KEEPER_H
#define UNTITLED1_KEEPER_H
#include "Employee.h"
// tell compiler Cage is a class
class Cage;
#include <string> // voor: std::string
#include <vector> // voor: std::vector<T>
#include <iostream> // voor: std::ostream
class Keeper : public Employee {
friend std::ostream& operator<<(std::ostream&, const Keeper&);
public:
Keeper(int number, const std::string& name, int age);
~Keeper();
/// Assign a cage to this animalkeeper
void setCage(Cage*);
/// Calculate the salary of this employee
float getSalary() const;
/// Print this employee to the ostream
void print(std::ostream&) const;
// =====================================
/// Save this employee to a file
void saveFile(std::ostream&) const;
protected:
private:
// Keepers only
Cage *cage = nullptr; // feeds animals in ...
};
Now i get the error on the const int number from the employee.h when i call boss->number in the saveFile method.
The error is on this line:
<< "\t" << cage->getKind() << "\t" << boss->number << endl;
because of boss->number
I have no idea why this happens and everywhere I read it said it should compile just fine but it doesnt.
Can anyone help?
Thank you~
The number member of the boss object is protected from direct access by functions outside of the object itself, even when owned by an object of the same type. The exceptions would be friend classes and methods, and copy constuctors.
In response to a comment: Inheritance is not your problem. The data in the object itself is protected from outside access. Your Keeper object inherits its own number member that it can access, as well as a pointer to a boss Employee. To fix your problem you can either make number public, or add an access method to return the value.

c++ getter not returning changed value outside class

I have 1 main class
class Vehicle{
private:
int fuel;
public:
int get_fuel(){ return this->fuel; }
void set_fuel(int fuel){ this->fuel = fuel; }
};
also 1 subclass of Vehicle
class Car : public Vehicle{
public:
Car();
};
Car::Car(){
set_fuel(500);
}
also my main.cpp file
#include <cstdlib>
#include <iostream>
#include "Vehicle.h"
#include "Car.h"
using namespace std;
int main(int argc, char *argcv[]){
Car c;
cout << c.get_fuel() << endl; //500
//set fuel to 200
c.set_fuel(200);
//print fuel again
cout << c.get_fuel() << endl;//still 500
}
why after using the setter the value still remains the same after i use the getter?
On VC++ 2012 your exact code works as expected. Output is 500 and 200.
class Vehicle {
private:
int _fuel;
public:
Vehicle(){
_fuel = 0;
}
int get_fuel(){
return _fuel;
}
// I like chainable setters, unless they need to signal errors :)
Vehicle& set_fuel(int fuel){
_fuel = fuel;
return *this;
}
};
class Car : public Vehicle {
public:
Car():Vehicle(){
set_fuel(500);
}
};
// using the code, in your main()
Car car;
std::cout << car.get_fuel() << std::endl; // 500
car.set_fuel(200);
std::cout << car.get_fuel() << std::endl; // actually 200
This is a slightly modified version. Place it in your .CPP file and try it. It can't not work!
PS: Stop using properties that have the same name as arguments. Always having to use this-> is very not cool! When you'll forget to use the this->, you'll see the bug of the century when you'll assign the value to itself and can't figure out what goes wrong.

c++ pointer vector<base_class*> put derived class but sliced print

I'm studying for pointer and inheritance of C++.\
I made pointer of vector Employee class which has name and salary in it.
Also, it has print function which printout name and salary.
I made it virtual
virtual void print() const;
Also here's the implementation of function
void Employee::print() const
{
cout << "Inquiry Employee info..." << endl;
cout << "Name:" << get_name() << "\n";
cout << "Salary:" << get_salary() << "\n" << "\n";
}
In derived class, I added one more private data Department Name and override print function.
I put derived class in pointer vector, and tried to call the function on derived function.
However, it only calls the function in base class.
When I make derived class object itself and called that print function, it worked.
What should I change to make derived class object in base class pointer vector can call function in derived class?
Addition ##
#ifndef MANAGER_H
#define MANAGER_H
#include <string>
#include<iostream>
#include "ccc_empl.h"
#include <iomanip>
class Manager : public Employee
{
public:
Manager();
Manager(string name, double salary, string dept);
~Manager();
virtual string get_department() const;
void print();
private:
string deptName;
};
#endif
implementation
#include <iostream>
#include <string>
#include "manager.h"
#include "ccc_empl.h"
Manager::Manager(){}
Manager::Manager(string name, double salary, string dept)
: Employee(name,salary)
{
deptName = dept;
}
Manager::~Manager(){}
string Manager::get_department() const
{
return deptName;
}
void Manager::print()
{
cout << "Inquiry Manager info..." << endl;
cout << "Name:" << get_name() << "\n";
cout << "Salary:";
cout << get_salary() << "\n";
cout << "Department:"<< get_department() << endl << endl;
}
You haven't shown us the Derived class print function, but I would guess that you forgot to declare it const. Easy mistake to make.

Static Data Members

Please have a look at the following code
GameObject.h
#pragma once
class GameObject
{
public:
GameObject(int);
~GameObject(void);
int id;
private:
GameObject(void);
};
GameObject.cpp
#include "GameObject.h"
#include <iostream>
using namespace std;
static int counter = 0;
GameObject::GameObject(void)
{
}
GameObject::GameObject(int i)
{
counter++;
id = i;
}
GameObject::~GameObject(void)
{
}
Main.cpp
#include <iostream>
#include "GameObject.h"
using namespace std;
int main()
{
//GameObject obj1;
//cout << obj1.id << endl;
GameObject obj2(45);
cout << obj2.id << endl;;
// cout << obj2.counter << endl;
GameObject obj3(45);
GameObject obj4(45);
GameObject obj5(45);
//Cannot get Static value here
//cout << "Number of Objects: " << GameObject
//
system("pause");
return 0;
}
Here, I am trying to record how many instances have been created. I know it can be done by a static data member, but I can't access it withing the Main method! Please help!
PS:
I am seeeking for a direct access, without a getter method
Your static variable, counter cannot be accessed because it isn't a member of GameObject. If you want to access the counter, you'll need to do something like this:
GameObject.h
#pragma once
class GameObject
{
public:
...
static int GetCounter();
...
};
GameObject.cpp
int GameObject::GetCounter()
{
return counter;
}
Then you can access the variable like:
cout << "Number of Objects: " << GameObject::GetCounter();
Of course, there are other ways of accessing a static variable, such as making the counter variable a static member of your GameObject class (which I would recommend).
In your code, counter is not a static member of your class, but just a good old global variable. You can read up on how to declare static member variables anywhere on the net, but here are some snippets:
GameObject.h
#pragma once
class GameObject
{
public:
GameObject(void);
GameObject(int);
~GameObject(void);
private:
int id;
// static members
public:
static int counter; // <<<<<<<<<<< declaration
};
ameObject.cpp
#include "GameObject.h"
int GameObject::counter = 0; // <<<<<<<<<<< instantiation
GameObject::GameObject(void)
{
counter++;
}
GameObject::GameObject(int i)
{
counter++;
id = i;
}
GameObject::~GameObject(void)
{
}
Main.cpp
#include <iostream>
#include "GameObject.h"
using namespace std;
int main()
{
GameObject obj2(45);
cout << "version one: " << obj2.counter << endl;
// second version:
cout << "version two: " << GameObject::counter << endl;
system("pause");
return 0;
}
Afaik accessing static members on an instance of that class should work fine, but it gives the wrong impression, you should prefer version two.
Never mind, I did it with a getter method. Closing thread