I was just wondering on the most efficient way of setting inherited members was and if the following code is alright to use:
This is the declaration of the base class:
class cEntity{
private:
int X, Y;
int Height, Width;
public:
cEntity();
cEntity(int x,int y,int h,int w);
~cEntity();
void setX(int x){X=x;};
void setY(int y){Y=y;};
void setCoords(int x, int y){X=x;Y=y;};
void setHeight(int h){Height = h;};
void setWidth(int w){Width = w;};
void setArea(int h, int w){Height=h;Width=w;};
int getX(){return X;};
int getY(){return Y;};
//void getXY(int,int);
int getHeight(){return Height;};
int getWidth(){return Width;};
//void getArea(int,int);
};
and here is the constructor of the derived class:
cOrganism::cOrganism () {
setCoords(0,0);
setArea(0,0);
Name = "UNKNOWN";
Health = 100;
MaxHealth = 100;
HealthHiRange =100;
HealthLoRange = 100;
};
So. Is is alright to call the setCoords() and setArea() in the derived class' constructor?
It's alright, but you can do much better by calling the base constructor:
cOrganism::cOrganism() : cEntity(0, 0, 0, 0) {
// other stuff
}
In fact, you should initialize your new, derived members the same way:
cOrganism::cOrganism()
: cEntity(0, 0, 0, 0),
Name("UNKNOWN"),
Health(100),
...
{
}
(You might also want to read up a bit on general C++ class design: If you expose getters and setters to all your private variables, something isn't quite right. A class is supposed to encapsulate a model, while you're doing essentially the opposite. But that's not a technical error.)
Much better to call it like this:
cOrganism::cOrganism () : cEntity(0,0,0,0) {
Name = "UNKNOWN";
Health = 100;
MaxHealth = 100;
HealthHiRange =100;
HealthLoRange = 100;
}
Or even better:
cOrganism::cOrganism ()
: cEntity(0,0,0,0), Name("UNKNOWN"), Health(100),
MaxHealth(100), HealthHiRange(100), HealthLoRange(100)
{}
That way the base class members are set as the base class implementation is constructed.
If the default constructor of the base class already intializes it to good values you don't have to do it all.
Otherwise the good solution is something like below.
class A
{
int x;
public:
A( int xin) :x(xin) {}
};
class B : public A
{
int y;
public:
B( int xin , int yin ) :A(xin) , y(yin) {}
};
Notice A(xin) in B constructor. This will called pass xin to the A constructor.
If you have something like integers it doesn't really matter what you do. But if A::X was actually a heavy weight object. With your approach A::x will be constructed once with default constructor and then assigned again when setCoords() is called from derived class constructor. My solution will ensure A::x* is only constructed once and that too with all the right value of its parameters.
More details here
Related
I am trying to create an "alien invaders" game by myself. In order to create enemies and player, I created a class called "entity" and made subclasses of it. Like Player, shootingEnemy, IdleEnemy. When coding I realised gathering them in a vector<Entity> would make my collision detection function much easier.
After searching on the internet I learned this is called "object slicing" and makes copies of of ony le base part of objects.
So the final version became this.
int main()
{
int BoardWidth = 50;
int BoardLength = 30;
vector<Bullet> bullets;
vector<Entity*> SpaceShips;
setup(SpaceShips, BoardWidth, BoardLength);
double ElapsedTime = 0;
int PreviousRoundSec = 0;
int PreviousRoundQSec = 0;
DrawGame(BoardWidth, BoardLength, SpaceShips, bullets);
int IsGameOver = 0;
auto start = chrono::steady_clock::now();
while(!IsGameOver)
{
// Updates EverySecond
if ((int)(ElapsedTime / 1000) > PreviousRoundSec)
{
PreviousRoundSec = (int)(ElapsedTime / 1000);
}
// Updates every quarter of a second
if ((int)(ElapsedTime / 250) > PreviousRoundQSec)
{
PreviousRoundQSec = (int)(ElapsedTime / 250);
}
// To keep time
auto end = chrono::steady_clock::now();
ElapsedTime = chrono::duration_cast<chrono::milliseconds>(end - start).count();
}
if (IsGameOver == 1)
{
// conjualations
}
else if (IsGameOver == 2)
{
// GameOver
}
return 0;
}
But when I try use some subclass specific functions I get an compiler error saying 'CLASS "Entity" does not have any member called "shoot"'.
I am trying to practice classes and polymorphism so I do not even know this has a solution because compiler doesn't have any way of knowing which element of this vector belongs to which subclass.
Also this is my classes header page in case needed.
class Entity
{
public:
int x;
int y;
int width;
int length;
int hp;
bool shooting;
public:
Entity(int x, int y, int width, int length, int hp, bool shooting): x(x), y(y), width(width), length(length), hp(hp), shooting(shooting) {}
};
class Bullet : public Entity
{
private:
char dir;
int ID;
public:
Bullet(int x, int y, char GivenDir, int GivenID) : Entity(x, y, 1, 1, 1, false) { dir = GivenDir; ID = GivenID; }
void Move();
void IfHit(vector<Entity>& SpaceShips);
void IfOut();
};
class Player : public Entity
{
private:
char action = 'a';
public:
Player(int x, int y, int hp) : Entity(x, y, 3, 2, hp, true) {}
void GetAction();
void Move();
void Shoot(vector<Bullet>& bullets);
bool IfHit(vector<Entity>& SpaceShips, vector<Bullet>& bullets);
};
class IdleEnemy : public Entity
{
public:
IdleEnemy(int x, int y, int hp) : Entity(x, y, 3, 2, hp, false){}
bool IfHit(Player* player, vector<Bullet> &bullets);
void Move(char HordDir);
};
class ShootingEnemy : public Entity
{
public:
ShootingEnemy(int x, int y, int hp) : Entity(x, y, 3, 2, hp, true) {}
void Shoot(vector<Bullet> &bullets);
bool IfHit(Player* player, vector<Bullet> &bullets);
void Move(char HordDir);
};
You need to check runtime polymorphism in C++. Let's check it out how can you do that. First of all, you need to change your Entity class interface. You need to add virtual or pure virtual functions. I have added pure virtual function;
class Entity
{
public:
int x;
int y;
int width;
int length;
int hp;
bool shooting;
public:
Entity(int x, int y, int width, int length, int hp, bool shooting) : x(x), y(y), width(width), length(length), hp(hp), shooting(shooting) {}
void virtual Move() = 0; // pure virtual function
void virtual IfHit() = 0; // pure virtual function
};
Virtual functions are overridable functions. Also, they have implementations but when we are talking about pure virtual functions they only provide an interface for the class. You need to override that function in your derived class. When you are implementing your derived class you need to do like this,
class Bullet : public Entity
{
private:
char dir;
int ID;
public:
Bullet(int x, int y, char GivenDir, int GivenID) : Entity(x, y, 1, 1, 1, false) { dir = GivenDir; ID = GivenID; }
void Move()override;
void IfHit();
void IfOut();
};
class Player : public Entity
{
private:
char action = 'a';
public:
Player(int x, int y, int hp) : Entity(x, y, 3, 2, hp, true) {}
void GetAction();
void Move();
void Shoot(vector<Bullet>& bullets);
void IfHit()override {//code};
};
class IdleEnemy : public Entity
{
public:
IdleEnemy(int x, int y, int hp) : Entity(x, y, 3, 2, hp, false) {}
void IfHit()override;
void Move()override;
};
class ShootingEnemy : public Entity
{
public:
ShootingEnemy(int x, int y, int hp) : Entity(x, y, 3, 2, hp, true) {}
void Shoot(vector<Bullet>& bullets);
void IfHit()override;
void Move()override;
};
These functions can be implemented either inline or in a source file. Also, there is an important point of these functions is the return value, function signature, and names' must be identical unless you do not use covariant return type.
As seen in the derived classes some of the functions are not common. I know your question how can I use that :) As mentioned ttemple in the comments you need to use dynamic_cast operator.
int main()
{
Entity* ptr = new ShootingEnemy{ 1,2,4 };
ptr->Move();
ptr->IfHit();
if (auto SE = dynamic_cast<ShootingEnemy*>(ptr))
SE->Shoot(...);
}
dynamic_cast operator is a runtime conversion operator. It converts the type of base class pointer to the derived class. It is called downcasting. Also, it checks that base class pointer points to the target derived class. If the dynamic_cast operation is completed with fail then it returns null and if statement becomes fail. Via that way, you can use runtime polymorphism and class member functions.
By the way, avoid object slicing as possible. You are losing derived class properties.
To better understanding please refer classes dynamic_cast
The compiler tells you the truth. You have a pointer to an Entity, which obviously does not have Shoot method in its interface, so how could you possibly call it without any cast?
The idea behind dynamic polymorphism which you are trying to implement here is about having a common interface (your base class, Entity), with specific implementation in each sub-class. So, publicly available methods signatures are going to be common for all subclasses, but not the implementations.
From the design perspective, cleanest approach would be to rename Entity to ShootableEntity and declare a pure virtual Shoot method in there. Then all sub-classes shall provide some implementation.
If not all of them implement Shoot, yet you are trying to use them generically in such manner, maybe you should reconsider the approach, eg. create two containers - for shootable entities and for non-shootable entities. Then, when iterating over shootable-entities (instances of classes which actually subclass ShootableEntity, which contain Shoot declaration), you could call Shoot on base class' pointer without any problems.
Your Entity does not represent any common interface, however. So, if you are trying to make use of polymorphism (so, you have a pointer to the base class, yet behind that pointer there's some concrete instance), such class won't do you any good.
In fact, the doc itself has a great explanation: http://www.cplusplus.com/doc/tutorial/polymorphism/
I've currently got code below in which i am trying to initialize the data members x, y and z to 0 when an object of type Solid is being instantiated. The lines 25, 26 and 27 contain errors, how would I rewrite these lines to access the x and y members and set them to 0?
edit 1: I've written out my code below.
edit 2: To clear things up, the only lines of code that can be altered are the lines that contain errors. The derived class should be rewritten to access the private data members.
class Shape
{
private:
int x, y;
protected:
string _type;
public:
Shape() { x = y = 0; }
Shape(int a, int b) { x = a; y = b; }
string type() { return _type; }
void stype(string val) { _type + val; }
int getx() { return x; }
int gety() { return y; }
};
class Solid : public Shape
{
int z;
public:
Solid() { x = y = z = 0; } // errors
Solid(int a, int b, int c) { x = a; y = b; z = c; } //
int Volume() { return x * y * z; } //
};
int main()
{
Solid ob1;
return 0;
}
You can't access private members of a base class, and the point of this exercise is that you don't need to - not that you should come up with a way of doing it.
Your default constructor should only set its own member - Shapes default constructor takes care of its own members:
Solid() { z = 0; }
or (the preferred method, which actually is initialisation and not an assignment)
Solid() :z(0) {}
The other constructor should initialise the base, and then z:
Solid(int a, int b, int c) : Shape(a,b), z(c){}
and Volume should use the provided accessors:
int Volume() { return getx() * gety() * z; }
Inherited class can not access to parent's private attributes. It can access his protected attributes, so you can move your variables to protected. Another option is to use setter function (like getX) and use them.
edit: change only for the relevant errors lines:
Solid():Shape(0,0) { this->z = 0; }
Solid(int a, int b, int c):Shape(a,b) { this->z = c; }
int Volume() { return this->getx() * this->get.y * this->z; }
when you create Solid object, you can also call for the c'tor of Shape with the values you want. That is the right way to initialize values of x, y when creating new inherited objects. For the third line calculation you should use getx() and gety() functions.
As said before, the key is to understand that x and y are not directly accessible for Solid object
You can't, directly, inherit the private members of the parent class. You could use its constructor in your derived class(child class) constructor though-its cool, but I don't use that way. Some information about the access specifiers(the type of inheritance you declare):
Public: Your derived class inherits the protected members of your parent class as protected and the public as public.
Protected: Your derived class inherits the protected members of your parent class as protected and the public as protected.
Private: Your derived class inherits the protected members of your parent class as private and the public as private.
Notice again that the private members of your parent class are not inherited. This should do the trick:
Change:
private:
int x, y;
Into:
protected:
int x, y;
Using the parent class constructor should look like:
class Solid : public Shape
{
private://doesn't matter, just for the aesthetics
int x;
int y;
int z;
public:
Solid() {
Shape();
z = 0; } // errors
And the direct way is(your code with added x,y as properties of the class):
class Solid : public Shape
{
private://doesn't matter, just for the aesthetics
int x;
int y;
int z;
public:
Solid() {x=y=z = 0; } // errors
Private data members are never inherited in any type of inheritance. Hence the name private, but interestingly you can use friend class concept here and even private data members are inherited now,
please try to run the following code:
#include <bits/stdc++.h>
using namespace std;
class Shape
{
private:
int x, y;
protected:
string _type;
public:
Shape() { x = y = 0; }
Shape(int a, int b) { x = a; y = b; }
string type() { return _type; }
void stype(string val) { _type + val; }
int getx() { return x; }
int gety() { return y; }
friend class Solid;
};
class Solid : public Shape
{
int z;
public:
Solid() { x = y = z = 0; } // errors
Solid(int a, int b, int c) { x = a; y = b; z = c; } //
int Volume() { return x * y * z; } //
};
int main()
{
Solid ob1;
return 0;
}
Now you can access x, y in inherited class also, since you declared class solid as friend of shape class.
Hope this answers your question.
In the following code, I would like to add new default argument 'z' to 'func' method without modifying subclasses. I get error C2259: 'CTest' : cannot instantiate abstract class error.
Is there anyway to do this without modifying all subclasses?
class ITest
{
public:
virtual void func(int x, int y, char c, int z = 1) = 0;
};
class CTest : public ITest
{
public:
void func(int x, int y, char c)
{
}
};
What you want is not directly possible. The existing classes don't know of the z parameter, so can't use it. If you want to provide some new subclasses whose clients will be aware of the z and be able to use it, you can do this:
class ITest
{
public:
virtual void func(int x, int y, char c) = 0;
virtual void func(int x, int y, char c, int z)
{ func(x, y, c); }
};
This way, old classes work just as before, as will clients who call the 3-parameter version. You're also giving the option of new subclasses using z and new clients using the 4-parameter version.
You have to modify your func() method in subclass in order to make it match the one from parent class. Either way, you'll get this error: cannot instantiate abstract class error.
You could add private data and initialize it as 1
class ITest
{
public:
ITest(): z(1) {}
virtual void func(int x, int y, char c) = 0;
private:
int z;
};
Hi I was coding simple class followed by sample code in web.
This code works fine without an error.
class Shape{
protected:
int width,height;
public:
Shape(int a = 0, int b=0)
{
width = a;
height = b;
}
};
class regSquare: public Shape{
public:
regSquare( int a=0, int b=0)
{
Shape(a, b);
}
};
but when I change my to have only one parameter for the constructor such as
class Shape{
protected:
int width;
public:
Shape(int a = 0)
{
width = a;
}
};
class regSquare: public Shape{
public:
regSquare(int a = 0)
{
Shape(a);
}
};
it occurring error with this massage
'error: declaration of `a' shadows a parameter'
I have no idea what is wrong about my code
Most likely neither version does what you want, though! The code
regSquare(int a = 0, int b = 0) {
Shape(a, b);
}
Does not initialize the Shape subobject of your regSquare object! Instead, it creates a temporary object of type Shape with the parameters a and b. The one parameter version does something similar:
Shape(a);
defines a default constructed object of type Shape called a. You probably meant to use the initializer list to pass the constructor arguments to the Shape subobject, e.g.:
reqSquare(int a = 0, int b = 0)
: Shape(a, b) {
}
or
regSquare(int a = 0)
: Shape(a) {
}
Because in single arguement compiler takes it as object name and creating an object so it is creating a conflict.
After reading up on class tutorials on the C++ site, I have learned the following piece of code which I then tried to work with:
class CVector {
public:
int x,y;
CVector () {};
CVector (int,int);
CVector operator + (CVector);
};
CVector::CVector (int a, int b) {
x = a;
y = b;
}
After which I wrote the following code, in order to learn to program C++ classes efficiently and to write cleaner code:
class Player {
public:
string name;
int level;
};
Player::Player(int y) {
level = y;
}
However it gives me error C2511: 'Player::Player(int)' : overloaded member function not found in 'Player'.
I have searched for the error but I did not find how to fix it. What's wrong with this code?
You need to declare the single parameter construction:
class Player {
public:
Player(int y);
std::string name;
int level;
};
Once you do this, there will no longer be a compiler synthesized default constructor, so if you need one, you would have to write your own. Also consider making the single parameter constructor explicit if you do not want implicit conversions from int.
class Player {
public:
explicit Player(int y); // no implicit conversions from int
Player() :name(), int() {} // default constructor and implementation
std::string name;
int level;
};
Also, prefer the constructor initialization list to assigning values in the constructor body, if possible. There are plenty of SO questions on that topic so I won't elaborate here. This is how you would do it:
Player::Player(int y) : level(y) {
}
Add declaration inside your class for this constructor.
class Player {
public:
Player( int y );
string name;
int level;
};
class Player
{
public:
Player(int );
string name;
int level;
};