I'm currently developing an RPG game using C++ and I got to the point of including events on the map.
I wanted to be able to have the event on the map heal the player. I figured the easiest way to do this was to pass a pointer to the event object from the game using the 'this' keyword. When I got into doing this there were a whole bunch of compiler errors that seem to have resulted from trying to include a class that was currently attempting to include the other class. (endless loop I guess?)
For example. I have my 'game' class and it has a public member belonging to the 'mapManager' class. The 'mapManager' object then has the 'event' object as a member. The 'game' object also has a 'player' object within its' members. I need to have the 'event' object change variables that the 'player' has. I could honestly throw pointers whenever I need them but this might get cumbersome.
What I'm trying to ask is if there is an easy way to have a child of a parent access another child of that parent or if it would just be easier to throw pointers to all of the child classes needing them pointing to the other children.
Wow... that made very little sense but hopefully someone can understand enough to give me a good answer. Here's some code in case it helps.
:game.h
include "player.h"
include "event.h"
class game
{
public:
player Player;
event Event;
};
:player.h
class player
{
public:
game* Game;
};
:event.h
class event
{
public:
game* Game;
};
Having just this results in "game does not name a type" and so I tried to include game in event.h and player.h and got the same error. What I want to do is be able to access player's variable HP from inside event.
It's preferable to avoid circular references where possible; however if you really want to do that, then the solution is to forward-declare your class Game at the top of the header files which will be using references/pointers to it. e.g.
#ifndef EVENTH
#define EVENTH
class Game;
class Event
{
Game* game;
};
#endif
and..
#ifndef PLAYERH
#define PLAYERH
class Game;
class Player
{
Game* game;
};
#endif
For header files which need no knowlege of the implementation/sizeof the Game class, a simple forward-declaration is sufficient to let the compiler know that a class with that name exists.
In your .cpp source files (where the implementation of Game is actually important and used by Player/Event implementation) you will still need to #include the header containing your Game class definition.
//game.h
class event;
class game {
event _e;
private:
game(){}
//game& operator=(game& other) {}
~game(){}
public:
static game & getInstance() {
static game instance;
return instance;
}
event& getEvent() {return _e;}
};
//HealEventObserver.h
class HealEventObserver {
public:
virtual void heal() = 0;
virtual ~HealEventObserver(){}
};
//player.h include game.h and HealEventObserver.h event.h
class Player : public HealEventObserver
{
public:
virtual void heal() {/*heal the player*/}
Player() {
game& instance = game::getInstance();
event& e = instance.getEvent();
e.registerObserver(this);
}
};
//event.h include HealEventObserver.h
class event {
std::set<HealEventObserver*> _observers;
void notify() {
std::set<HealEventObserver*>::iterator it = _observers.begin();
std::set<HealEventObserver*>::iterator end = _observers.end();
for( ;it!=end; ++it) {
it->heal();
}
}
public:
void registerObserver(HealEventObserver* observer) {_observers.insert(observer);}
};
Don't make your event object change the player at all just make the event tell the player to heal himself. Also if game is suppose to represent everything then make it global.
To Answer the comment: (This is just my opinion and nothing else.)
After a bit of research i found this link that gives the names of great references.
The Definitive C++ Book Guide and List
Related
everyone. I'm working on a final project for school and it's coming along great, but I've run into a bit of a problem with trying to use a pointer to a pointer. I'll do my best to explain the problem below:
So I have a class called Player that sort of looks like this:
class Player
{
Player();
int health;
void adjustHealth(int);
};
Player::Player()
{
health = 40;
}
void Player::adjustHealth(int adjust)
{
health += adjust;
}
I have another class called Shelter, that include "Player.h" and looks a little like this:
class Shelter
{
Shelter();
Player* player; // Create a pointer to Player class.
};
In the Shelter header file, I have the following in my default constructor:
Shelter::Shelter()
{
...Other code here.
player = new Player();
}
In the Shelter header file, I use this new player for things like:
player->adjustHealth(-1); // Subtract one health from the player.
Which works great.
The problem I'm facing is with creating another class called Church, that is in a separate header file and acts as a separate location in the game. I want Church to use the same player that Shelter does, so it has all of the same stats, etc, rather than creating a new player in Church (which is what I did in Shelter.h).
Right now, I have something like:
class Church
{
Church();
Shelter **cplayer; // This is supposed to be the pointer to the pointer.
};
The default constructor is where I'm having my problem. I want to use the same player from Shelter, not create a new player like I did in Shelter.
Church::Church
{
What should I do here?
}
I've tried a number of things, but I can't quite get it working. Eventually I want to be able to do something like this:
player->adjustHealth(-1); // Subtract one health from the player.
Only in Church, so that player's stats, like health, are adjusted no matter which location they are in.
I hope my question makes sense. If not, I can try to clarify better. Anyway, thanks in advance.
The problem I'm facing is with creating another class called Church, that is in a separate header file and acts as a separate location in the game. I want Church to use the same player that Shelter does, so it has all of the same stats, etc, rather than creating a new player in Church
This sounds like an ideal situation to use std::shared_ptr.
class Shelter
{
Shelter();
std::shared_ptr<Player> player; // Create a pointer to Player class.
// Provide a public accessor
public:
std::shared_Ptr<Player> getPlayer() const { return player; }
};
and
class Church
{
Church(std::shared_ptr<Player> pl) : player(pl) {}
std::shared_ptr<Player> player;
// You haven't explained in your post why you need this.
// Maybe you don't need it.
// Shelter** shelter;
};
I'm pretty new to C++ and I am working in a little roguelike game. I have a generic class named Actor, which has 2 child classes, NPC and Player. The idea is for each child to contain specific data, such as experience provided by killing an NPC or the Player's stats, and special methods. On the other hand, Actor contains general methods such as move, because both player and NPC should move.
Now I have a vector of NPC pointers, and my move method should check if the target tile is occupied by an NPC (and some other NPC info), but I don't have access to that class from Actor. I added a forward declaration to NPC inside of Actor, but then I get this error:
pointer to incomplete class type is not allowed
because forward declaration is not enough to access NPC methods.
Actor.h:
class NPC; // Forward declaration.
class Actor
{
public:
void move(std::vector<std::unique_ptr<NPC>> & NPCs);
}
Actor.cpp:
void Actor::move(std::vector<std::unique_ptr<NPC>> & NPCs)
{
// Go through the NPCs.
for (const auto &NPC : NPCs)
{
if (NPC->getOutlook() > 0) ... // Error.
}
}
I could put the move method inside both NPC and Player, but I would be duplicating code, and that's a pretty bad idea.
What would be the best solution here? I guess there is a better way to organize this, but it seems pretty logical as it is. Maybe some kind of inheritance or virtual functions magic?
Thanks! :)
You will need to include the header where NPC is defined in Actor.cpp, otherwise the definition of NPC will be missing.
// Actor.cpp
#include "NPC.h"
void Actor::move(std::vector<std::unique_ptr<NPC>> & NPCs)
{
// Go through the NPCs.
for (const auto &NPC : NPCs)
{
if (NPC->getOutlook() > 0) ... // Now you'll be able to access this.
}
}
(it is be possible that this question has been asked very often already and i am sorry about this repost, but anything i found just didnt help me, since i am relatively a beginner at c++)
so here is an example to show my problem
i have the class monster
class Monster{
public:
Monster();
void attack();
private:
int _health;
int _damage;
};
and i have the class Level
class Level{
Level();
};
i have created the object "snake" from the class Monster in my "main.cpp"
#include "Monster.h"
int main(){
Monster snake;
}
now what do i do if i want to use "snake" in my "Level" class? if i want to do "snake.attack();" inside of "Level.cpp" for example?
If i declare it again in "Level.cpp" it will be a seperate object with its own attributes wont it?
i have always been making the member functions of my classes static until now, so i could do "Monster::attack();" anywhere in my program but with this tachnique i cant have multiple objects doing different things depending on their attributes (snake1, snake2, bat1, etc...)
thanks for the help in advance!
(and sorry for the possibly reoccuring question)
Presuming those snips are your .h files.
Your level.cpp should something like this:
#include "level.h" // its own header
#include "monster.h" // header with Monster::attack() declaration
Level::DoAttack(Monster& monster) { // using snake as parameter.
health = health - monster.attack(); // monster hits us, subtract health.
}
monster.h would be
class Monster{
public:
Monster();
void attack();
private:
int _health;
int _damage;
};
and monster.cpp
Monster::attack() {
// code to calculate the attack
}
I could not completely understand your questions.But from what I understood.I think you want to access a Monster object instantiated in main() to be used inside level.So,here is what you can do.Add a constructor inside the level class which takes a monster object as an argument.Then instantiate a level object and pass the monster object in it.Like this,
Level l=new Level(snake);
By declaring a class you're not creating any objects. You normally declare a class by including the corresponding header file.
So, in Level.h you'd #include <Monster.h>, then you can reference it inside Level.
But seriously, you can't write much C++ code without understanding the basic things such as declaration vs. definition, header files (.h), classes vs. objects, pointers and references, etc. It would be best to invest in a book or at least to read some tutorials online.
I am working on a little game engine but I got stuck at something. Explanation : I have two classes, cEntity And ObjectFactory :
cEntity
class cEntity:public cEntityProperty
{
Vector2 position;
Vector2 scale;
public:
cEntity(void);
cEntity(const cEntity&);
~cEntity(void);
public:
void init();
void render();
void update();
void release();
};
ObjectFactory
#include "cEntity.h"
#include <vector>
class ObjectFactory
{
static std::vector<cEntity> *entityList;
static int i, j;
public:
static void addEntity(cEntity entity) {
entityList->push_back(entity);
}
private:
ObjectFactory(void);
~ObjectFactory(void);
};
std::vector<cEntity> *ObjectFactory::entityList = new std::vector<cEntity>();
Now I am adding new cEnity to ObjectFactory in cEntity constructor but facing an error related to circular references: for using ObjectFactor::addEntity() I need to define the ObjectFactory.h in cEntity class but it creates a circular reference.
I think your code might have an underlying architectural issue given how you have described the problem.
Your ObjectFactory should be handling the cEntities, which in turn should be unaware of the "level above". From the description of the problem you are having, it implies that you're not sure what class is in charge of what job.
Your cEntitys should expose an interface (i.e. all the stuff marked "public" in a class) that other bits of code interact with. Your ObjectFactory (which is a bit badly named if doing this job, but whatever) should in turn use that interface. The cEntitys shouldn't care who is using the interface: they have one job to do, and they do it. The ObjectFactory should have one job to do that requires it to keep a list of cEntitys around. You don't edit std::string when you use it elsewhere: why is your class any different?
That being said, there's two parts to resolving circular dependencies (beyond "Don't create code that has circular dependencies in the first place" - see the first part to this answer. That's the best way to avoid this sort of problem in my opinion)
1) Include guards. Do something like this to each header (.h) file:
#ifndef CENTITY_H
#define CENTITY_H
class cEntity:public cEntityProperty
{
Vector2 position;
Vector2 scale;
public:
cEntity(void);
cEntity(const cEntity&);
~cEntity(void);
public:
void init();
void render();
void update();
void release();
};
#endif
What this does:
The first time your file is included, CENTITY_H is not defined. The ifndef macro is thus true, and moves to the next line (defining CENTITY_H), before it moves onto the rest of your header.
The second time (and all future times), CENTITY_H is defined, so the ifndef macro skips straight to the endif, skipping your header. Subsequently, your header code only ever ends up in your compiled program once. If you want more details, try looking up how the Linker process.
2) Forward-declaration of your classes.
If ClassA needs a member of type ClassB, and ClassB needs a member of type ClassA you have a problem: neither class knows how much memory it needs to be allocated because it's dependant on another class containing itself.
The solution is that you have a pointer to the other class. Pointers are a fixed and known size by the compiler, so we don't have a problem. We do, however, need to tell the compiler to not worry too much if it runs into a symbol (class name) that we haven't previously defined yet, so we just add class Whatever; before we start using it.
In your case, change cEntity instances to pointers, and forward-declare the class at the start. You are now able to freely use ObjectFactory in cEntity.
#include "cEntity.h"
#include <vector>
class cEntity; // Compiler knows that we'll totally define this later, if we haven't already
class ObjectFactory
{
static std::vector<cEntity*> *entityList; // vector of pointers
static int i, j;
public:
static void addEntity(cEntity* entity) {
entityList->push_back(entity);
}
// Equally valid would be:
// static void addEntity(cEntity entity) {
// entityList->push_back(&entity);}
// (in both cases, you're pushing an address onto the vector.)
// Function arguments don't matter when the class is trying to work out how big it is in memory
private:
ObjectFactory(void);
~ObjectFactory(void);
};
std::vector<cEntity*> *ObjectFactory::entityList = new std::vector<cEntity*>();
The qml viewer (for 4.8 and 5.0) is implemented like that:
In the .h(eader) we have:
class QtQuick2ApplicationViewer : public QQuickView
{
Q_OBJECT
...
private:
class QtQuick2ApplicationViewerPrivate *d;
};
Then in the .CPP file:
class QtQuick2ApplicationViewerPrivate
{
QString mainQmlFile;
friend class QtQuick2ApplicationViewer;
static QString adjustPath(const QString &path);
};
QtQuick2ApplicationViewer::QtQuick2ApplicationViewer(QWindow *parent)
: QQuickView(parent)
, d(new QtQuick2ApplicationViewerPrivate())
{
connect(engine(), SIGNAL(quit()), SLOT(close()));
setResizeMode(QQuickView::SizeRootObjectToView);
#ifdef Q_OS_ANDROID
engine()->setBaseUrl(QUrl::fromLocalFile("/"));
#endif
}
Why is using friend necessary here? I don't see any reason why would anybody use a friend class. Is there any real use for friend classes (except for exotics that anybody could live without)?
.h
#include
class QtQuick2ApplicationViewer : public QQuickView
{
Q_OBJECT
public:
explicit QtQuick2ApplicationViewer(QWindow *parent = 0);
virtual ~QtQuick2ApplicationViewer();
void setMainQmlFile(const QString &file);
void addImportPath(const QString &path);
void showExpanded();
private:
class QtQuick2ApplicationViewerPrivate *d;
};
.cpp
#include "qtquick2applicationviewer.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtQml/QQmlEngine>
class QtQuick2ApplicationViewerPrivate
{
QString mainQmlFile;
friend class QtQuick2ApplicationViewer;
static QString adjustPath(const QString &path);
};
QString QtQuick2ApplicationViewerPrivate::adjustPath(const QString &path)
{
#ifdef Q_OS_UNIX
#ifdef Q_OS_MAC
if (!QDir::isAbsolutePath(path))
return QString::fromLatin1("%1/../Resources/%2")
.arg(QCoreApplication::applicationDirPath(), path);
#elif !defined(Q_OS_ANDROID)
const QString pathInInstallDir =
QString::fromLatin1("%1/../%2").arg(QCoreApplication::applicationDirPath(), path);
if (QFileInfo(pathInInstallDir).exists())
return pathInInstallDir;
#endif
#endif
return path;
}
QtQuick2ApplicationViewer::QtQuick2ApplicationViewer(QWindow *parent)
: QQuickView(parent)
, d(new QtQuick2ApplicationViewerPrivate())
{
connect(engine(), SIGNAL(quit()), SLOT(close()));
setResizeMode(QQuickView::SizeRootObjectToView);
#ifdef Q_OS_ANDROID
engine()->setBaseUrl(QUrl::fromLocalFile("/"));
#endif
}
QtQuick2ApplicationViewer::~QtQuick2ApplicationViewer()
{
delete d;
}
void QtQuick2ApplicationViewer::setMainQmlFile(const QString &file)
{
d->mainQmlFile = QtQuick2ApplicationViewerPrivate::adjustPath(file);
setSource(QUrl::fromLocalFile(d->mainQmlFile));
}
void QtQuick2ApplicationViewer::addImportPath(const QString &path)
{
engine()->addImportPath(QtQuick2ApplicationViewerPrivate::adjustPath(path));
}
void QtQuick2ApplicationViewer::showExpanded()
{
#if defined(Q_WS_SIMULATOR)
showFullScreen();
#else
show();
#endif
}
Friends examine friends' privates. You sure can do without access restrictions at all, but once you use it, being friendly helps in intimate situations.
class Me;
class You {
friend class Me;
private:
Home _home;
Car _car;
public:
void bar(Me my);
};
class Me {
Stuff _stuff;
public:
foo(You you) {
//If you consider me a friend
you._home.enter(); //I can enter your `private _home`
you._car.drive(); //I can drive your `private _car`.
}
};
void You::bar(Me my) {
my.stuff //this is an error because I don't consider you a friend so you can't touch my `private _stuff`.
}
Knowing you can always count on me, for sure. That's what friends are for. http://www.youtube.com/watch?v=xGbnua2kSa8
But I guess you're asking about friend classes in C++.
The whole point of "scope" is to define exactly who can see what in another class. You don't "need friends" any more than you need "protected" or "private", in the sense that you could make everything in all your classes public, and your program would successfullly compile and run. But the idea is to establish -- and document -- exactly what is the public interface of a class, and thus cannot be changed without considering the impact on other classes, and what is an internal implementation, which can be freely re-worked or re-organized without fear of impacting other classes.
So the point of a "friend" is to say: Hey, I have this class X, and this other class Y. And in general other classes don't need to know how X goes about doing it's job. But Y interacts with some low-level thing in X, so it needs to see it. Thus I make Y a friend of X. Like, I have an Investor class that has a function that (presumably among other things) has a function to calculate the total amount of a customer's investments. In general, other classes shouldn't care how I do that calculation: they just want the total. But now I have a TaxReporting class that needs to know how much of that balance is in taxable securities and how much is in non-taxable securities. Maybe I don't want to make these functions public because the information is confidential and I want to limit access for real-world privacy reasons. More often, I don't want to make it public because the calculation is tricky or subject to frequent change, and I want to keep tight control on what classes access it to limit the problems caused when things change. So I make TaxReporting a friend so it can access some functions that make the distinction, without opening these to the world.
In practice, when I was doing C++ I rarely used friends. But "rarely" is not "never". If you find yourself saying, "Oh, I have to make this public just so this one other class can see it", then maybe instead of making it public you should make a friend.
"friend" is super useful and something you want to use all the time.
Typical use cases are:
You have a class that uses subclasses where the subclass is allowed to use private functions of the class that owns the subclasses:
class ManagedObject
{
public:
void doStuff() { mMgr->updateManager(); }
private:
Manager* mMgr;
};
class Manager
{
friend ManagedObject;
public:
ManagedObject* createManagedObject();
private:
void updateManager() { }
};
So in this case you have a class that creates and deals with "managedObject". Whenever this object is manipulated it needs to update the object that created it. You want users of your class to know that they don't ever need to call "updateManager" and in fact wat to generate a compile time error if they do.
Another common case is when you have a function which acts like a class member but cannot for some reason be a class member. An example is operator<<. If you write your own io stream class, or if you want to create a serialization system that users operator<<:
class serializedObject
{
public:
friend Serializer& operator<< ( Serializer& s, const serializedObject& obj );
protected:
u32 mSecretMember;
};
Serializer& operator<<( Serializer& s, serializedObject& obj )
{
serializer << obj.mSecretMember;
return s;
}
In this case the serialization function cannot be a member of serializedObject, but needs to look at the internals of serializedObject to serialize it. You will see similar patterns of you create other operators ( like addition ) where the RHS of the operator is not the same class as the LHS
In Qt, there is something called a 'guarantee of binary compatibility', which means that your app can run against Qt4.8, 4.8.1, and 4.8.2 and so forth without recompiling.
In order to achieve this the vtable for objects cannot change. So, Qt classes are written using the "PIMPL" (pointer to implementation) idiom.
The "Private" class is the PRIVATE implementation of the public class - it is an implementation detail of QtQuick2ApplicationViewer. No one in the whole world knows about the private class except the public class. These two classes are deeply intertwined by design. In fact, they are really different aspects of a single object that has been partitioned c++ wise in order to achieve the binary compatibility guarantee.
It is reasonable in this context that the private class can access the public class.
2) In this context quit is not QApplication::quit(), that is slot of cause, but some internal signal of engine().