So, I'm trying to reproduce one thing I learned in Java in my C++ program and I just can't make this work!
Here's a example of what I want to do:
class Game{
public:
int screenWidth, screenHeight;
Screen* titleScreen;
void createScreen(){
titleScreen = new Screen(this);
}
}
class Screen{
public:
Game* game;
Rect quad1;
Screen(Game* game){
this->game = game;
quad1.x = game->screenWidth/2;
}
}
I'm not even sure if this code is right because I created it right now just to show what I want to do.
So, basically, what I want to do is create a reference for "Game" inside "Screen" so I can use its atributes and methods(in this case, the screen width), even though "Screen" is being instantiated inside "Game". I did something like this in Java and it worked perfectly, but for C++ I get so many erros that I don't even know how to interpret them... I tried using pointer for the parameters and instead of using "this" I tried using "&this" but none of them worked and I get pratically the same errors...
So, what am I doing wrong? How can i make this work? Is this even possible in C++?
Use a forward declaration and define the function after the definition of the things it needs.
class Screen; // Forward declaration
class Game{
public:
int screenWidth, screenHeight;
Screen * titleScreen;
void createScreen();
}
class Screen{
public:
Game* game;
Rect quad1;
Screen(Game *game){
this->game = game;
quad1.x = game->screenWidth/2;
}
}
// Out-of-line definition.
// This should be declared "inline" if it's in a header file.
void Game::createScreen(){
titleScreen = new Screen(this);
}
a)Make forward declaration of Game class.
b)Make Screen(Game *game) constructor to accept a pointer not an object since you are passing this pointer.
Refer following sample
http://ideone.com/J8He9f
Related
I'm facing this novice issue. Assume the class MainFrame (the following code isn't going to compile - I'm trying to give a basic idea of what I'm doing because I think my problem is easy to solve by someone more knowledgeable than me) which lives on file gui.cxx along with other functions. Note that this is part of a larger project so I'm skipping the main.cxx which I have included gui.h.
In the function start_gui_with_config() I'm trying to use an object from MainFrame. At the moment is declared as private so I'm expecting to have an text_data_path was not declared in this scope.
I also declared this variable as public and static in the class definition in gui.h but then I get the same error when using either text_data_path ->SetText(data_path);.
When I'm using MainFrame::text_data_path ->SetText(data_path); (still text_data_path is declared as private and static) I get the error undefined reference to MainFrame::text_data_path in any line I'm using text_data_path within the MainFrame::MainFrame constructor (file gui.cxx) and strangely I get this error twice for each line.
Finally I tried making all the functions (start_gui(), start_gui_with_config()) part of MainFrame and I declared them as either static void (in this case I got an error error: cannot declare member function static void MainFrame::start_gui_with_config() to have static linkage on the gui.cxx ) or void (in this case I got the error error: cannot call member function void MainFrame::start_gui_with_config() without object on the main.cxx).
Any idea on how to use text_data_path in a function (i.e. start_gui_with_config()) that doesn't belong to the class?
gui.cxx
#include "../include/gui.h"
MainFrame::MainFrame(const TGWindow *p, UInt_t width, UInt_t height):TGMainFrame(p, width, height, kMainFrame|kHorizontalFrame){
// Define widgets
text_data_path = new TGTextEntry("/data/2020");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This is a virtual constructor
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MainFrame::~MainFrame() {
// Clean up used widgets: frames, buttons, layout hints
Cleanup();
}//_____MainFrame::~MainFrame()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This is to start the GUI with default settings
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void start_gui(){
// Popup the gui
std::cout << "Starting the gui" << std::endl;
new MainFrame(gClient->GetRoot(), 1000, 800);
}//_____start_gui()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This is to start the GUI using the configuration file from previous session
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void start_gui_with_config(){
TString data_path = gSystem->GetFromPipe("awk '{if(NR==1) print $NF}' Config/last_session.cfg.viewer");
start_gui();
MainFrame::text_data_path->SetText(data_path);
}//____MainFrame::start_gui_with_config()
gui.h
#ifndef ___GUI_H
#define ___GUI_H
//ROOT Includes
#include <TGTextEntry.h>
//C++ includes
using namespace std;
class MainFrame : public TGMainFrame {
private:
// Widgets
TGTextEntry *text_data_path;
public:
// Widgets
//static TGTextEntry *text_data_path;
MainFrame(const TGWindow *p, UInt_t width, UInt_t height);
virtual ~MainFrame();
//void start_gui_with_config();
//static void start_gui();
ClassDef (MainFrame,0);// Remove for ROOT6 and rootcling
};
void start_gui();
void start_gui_with_config();
#endif
I suggest you use a setter on the MainFrame class:
void setDatapathText(TString const& newDatapath) {
text_data_path->SetText(data_path);
}
You can then call it like so in your start_gui_with_config function :
auto frame = MainFrame(p, w, h);
frame.setDatapathText(data_path);
Be careful, your code clearly has memory management problems, and as a general rule you should never deal with raw new and delete outside of smart pointers. I suggest making sure you are comfortable with dynamic allocation, else I'm afraid you will be facing hard-to-debug errors earlier than expected
Your problem is you throw away the pointer to your MainFrame so you have no way to access it in start_gui_with_config() after you created the MainFrame.
One way to fix this is to change the signature of void start_gui(); to MainFrame* start_gui(); in your gui.h header.
In the gui.cxx change the implementation to
MainFrame* start_gui() {
return new MainFrame(gClient->GetRoot(), 1000, 800);
}
And then in your start_gui_with_config() use the pointer like this:
void start_gui_with_config(){
TString data_path = gSystem->GetFromPipe("awk '{if(NR==1) print $NF}' Config/last_session.cfg.viewer");
MainFrame* frame = start_gui();
frame->text_data_path->SetText(data_path);
}//____MainFrame::start_gui_with_config()
This code assumes the MainFrame object destroys itself otherwise the code will leak memory. I assume this destruction happens after the window closes. I have seen other GUI frameworks like Qt do this.
Cocos2d-x 2.1rc0
OS X 10.8, XCode 4.6.2
Playing around with the HellowWorld with Box2D example to gain some concepts.
Creating an class that is an extension of CCLayerColor.
Previously, before I created a separate object I was doing:
// background
CCLayerColor *background = CCLayerColor::create(cGhostWhite);
background->setContentSize(CCSizeMake(1024, 768));
background->setPosition(0,0);
this->addChild(background,0);
This worked. After trying to create my own object I am getting and error:
error: no viable conversion from 'PlainBackgroundLayer::PlainBackgroundLayer' to 'PlainBackgroundLayer::PlainBackgroundLayer *'
Here is what I am doing:
PlainBackgroundLayer.h:
#ifndef __PLAINBACKGROUNDLAYER_H__
#define __PLAINBACKGROUNDLAYER_H__
#include "cocos2d.h"
#include "Box2D.h"
class PlainBackgroundLayer : public cocos2d::CCLayerColor
{
public:
PlainBackgroundLayer(cocos2d::ccColor4B inColor);
~PlainBackgroundLayer();
virtual void draw();
private:
cocos2d::ccColor4B backgroundColor;
cocos2d::CCSize layerSize;
cocos2d::CCLayerColor *background;
};
#endif // __PLAINBACKGROUNDLAYER_H__
PlainBackgroundLayer.cpp:
#include "PlainBackgroundLayer.h"
using namespace cocos2d;
PlainBackgroundLayer::PlainBackgroundLayer(cocos2d::ccColor4B inColor)
{
layerSize = CCDirector::sharedDirector()->getWinSize();
backgroundColor = inColor;
background = CCLayerColor::create(backgroundColor);
background->setContentSize(CCSizeMake(1024, 768));
background->setPosition(0,0);
}
PlainBackgroundLayer::~PlainBackgroundLayer()
{
delete background;
}
and instantiating like:
PlainBackgroundLayer::PlainBackgroundLayer *background = PlainBackgroundLayer::PlainBackgroundLayer(cGhostWhite);
this->addChild(background,0);
What am I doing wrong? I feel like I am doing this correctly.
UPDATE 1: now I am doing:
in .cpp:
static PlainBackgroundLayer* PlainBackgroundLayer::create(cocos2d::ccColor3B inColor)
{
// create functions should return autoreleased objects.
PlainBackgroundLayer* layer = new PlainBackgroundLayer();
layer->setColor(inColor);
return layer->autorelease();
}
in .h:
class PlainBackgroundLayer : public cocos2d::CCLayerColor
{
public:
static PlainBackgroundLayer* create(cocos2d::ccColor3B &var);
virtual void draw();
};
and I am getting errors in the .cpp:
`Out-of-line definition of 'create' does not match any declaration in 'PlainBackgroundLayer'`
`'static' can only be specified inside the class definition`
`Cannot initialize return object of type 'PlainBackgroundLayer *' with an rvalue of type 'cocos2d::CCObject *'`
Notice that you are both subclassing CCLayerColor, and you also have a member variable called 'background' that is a CCLayerColor. I suspect you might be misunderstanding how inheritance works. Usually you want one or the other. You might look at 'is a' vs 'has a' relationships if this is the case.
On top of this, you don't actually add the 'background' member variable to the scene, so it will have no effect. Also you shouldn't delete CCNode based objects, and you don't even need to call release on most, since they are usually autoreleased and managed by the scene.
What you probably want to do is remove the background member variable, and define a new create method like this, with a constructor that does nothing. (Note:I haven't tested this code):
// this goes in your PlainBackgroundLayer.h's public method section.
static PlainBackgroundLayer* create(ccColor3B &var);
// in your cpp: (EDIT: removed static keyword, and make all instances set size/pos)
PlainBackgroundLayer* PlainBackgroundLayer::create(ccColor3B &var)
{
// create functions should return autoreleased objects.
PlainBackgroundLayer* layer = new PlainBackgroundLayer();
layer->setColor(var);
layer->setContentSize(CCSizeMake(1024, 768));
layer->setPosition(0,0);
return layer->autorelease();
}
// you can omit this and use default constructor as well. I just want to point out
// that the constructor doesn't need to do anything
PlainBackgroundLayer::PlainBackgroundLayer()
{
}
The advantage of inheritance is that you can treat derived classes in a similar fashion.
Now you can instantiate and add to the scene the same way you did before:
// background
PlainBackgroundLayer *background = PlainBackgroundLayer::create(cGhostWhite);
this->addChild(background,0);
try:
PlainBackgroundLayer *background = new PlainBackgroundLayer(cGhostWhite);
this->addChild(background,0);
Say that I have this object:
class Game{
public:
void SetPointer(D2DResources&);
public:
D2DResources* pD2DResources;
};
with this function:
void Game::SetPointer(D2DResources& p)
{
pD2DResources=&p;
}
And I do that in my WinMain:
Game game;
D2DResources d2DResources();
game.SetPointer(d2DResources);
Will it work? If not, what is the correct way to do it? The idea is to later access d2DResources' functions like this:
pGame->pD2DResources->OnRender();
pGame being a pointer to the above game object.
As long as the pointed-to instance is kept alive, I see no problem with your approach. But it seems you want to declare the instance in a function WinMain, in which case it won't work.
Let's get one nit out of the way first: The following line
D2DResources d2DResources();
will declare a function which returns a D2DResources and with no parameters and not a variable of type D2DResources. If you want the latter, drop the brackets:
D2DResources d2DResources;
Now, if you want to keep the instance alive for a longer time, you should use a std::shared_ptr. An example could look like this:
class Game{
public:
void SetPointer(D2DResources&);
public:
std::shared_ptr<D2DResources> pD2DResources;
};
void Game::SetPointer(std::shared_ptr<D2DResources> p)
{
pD2DResources=p;
}
and in WinMain, use:
Game game;
auto d2DResources = std::make_shared<D2DResources>();
game.SetPointer(d2DResources);
the usage stays the same as you wanted.
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
I'm sure this has something to do with virtual functions, but I'm struggling to work out how.
Here is my (simplified) situation:
Roughly what the program does is have one pair of files (computer.h) draw a computer with a blank screen, and another pair (program.h) which has a function that needs to draw on that computer screen
The computer class is going to be re-used in many different situations, so the screen draw function needs to be passed in a generic fashion
in computer.h:
include "screen.h"
class computer {
void drawComputer(); //this function draws a picture of a computer
void drawMonitor();
};
in computer.cpp:
void computer::drawComputer(){
//draws all the components then the monitor
drawMonitor(); //this is where the external function (from class screen) needs to execute
}
void computer::drawMonitor(){
//draws the background and border of screen
}
in program.h:
class program {
//many other program functions
void drawScreen();
};
in program.cpp:
//many other program functions
void program::drawScreen(){
//this function draws the contents of the screen
}
My question is, from program.cpp, how do I 'send' the drawScreen() function to execute within the drawMonitor() function in computer.cpp?
Edit
#Chris' solution seems to be nearly exactly what I am after, however when I attempt to implement it I get the following errors:
testApp.h:40: error: 'testApp::prog' cannot appear in a constant-expression
testApp.h:40: error: `&' cannot appear in a constant-expression
testApp.h:40: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression
testApp.h:40: error: ISO C++ forbids initialization of member 'isprog'
testApp.h:40: error: making 'isprog' static
testApp.h:40: error: invalid in-class initialization of static data member of non-integral type 'IScreen*'
testApp.h:41: error: 'isprog' has not been declared
testApp.h:42: error: ISO C++ forbids declaration of 'comp1' with no type
testApp.h:42: error: expected ';' before '.' token
The lines are
39 Program prog;
40 IScreen *isprog = dynamic_cast<IScreen*>(&prog);
41 OP1 comp1(isprog);
42 comp1.drawScreen();
Anyone know where I'm going wrong with the implementation?
Well you're half-way there. For something like this, yes I'd use virtual functions (in order to define an abstract interface). Here's the basic outline of how I'd do it:
// First create a class to define an interface for drawing a screen
class IScreen
{
public:
// Defines an interface named drawScreen
virtual void drawScreen() = 0;
};
// Next actually implement the interface
class Program : public IScreen
{
public:
// Here we actually implement it
virtual void drawScreen()
{
// Draw some stuff here
}
};
// You can implement this more than once if you want
class BlueScreenOfDeathScreen : public IScreen
{
public:
virtual void drawScreen()
{
// Draw a BSOD on the screen
}
};
// Finally, use the interface
class Computer
{
private:
IScreen* myScreen;
public:
Computer(IScreen* screen)
: myScreen(screen)
{
}
void drawComputer()
{
// ...
}
void drawMonitor()
{
// Draw the monitor
// ...
// Draw the screen
myScreen->drawScreen();
}
};
Doing it this way, you can easily define multiple IScreen implementations and quickly swap them out with minimal changes to your code.
// Render using the "Program" class
Program prog;
IScreen *iprog = dynamic_cast<IScreen*>(&prog);
Computer comp1(iprog);
comp1.drawScreen();
// Render using the "BlueScreenOfDeathScreen" class
BlueScreenOfDeathScreen bsod;
IScreen *ibsod = dynamic_cast<IScreen*>(&bsod);
Computer comp2(ibsod);
comp2.drawScreen();
Easy, no?
You'd have to create an instance of program in your computer class, like so:
Program mypgm;
and then within your
void computer::drawMonitor(){
//draws the background and border of screen
mypgm.DrawScreen();
}
The most straight forward answer is to have an object of program inside computer and call drawScreen() from within. i.e.
class computer {
program prg; // <--- internal object
//...
};
void computer::drawMonitor() {
prg.drawScreen();
}
Another way is to pass an reference object of program to drawMonitor and call the method. i.e.
void computer::drawMonitor(program &prg) { // <--- pass by reference
prg.drawScreen();
}