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.
Related
First things first, I think it will make more sense to see my code. Header:
#include <vector>
#include "GUIItem.h"
class WindowManager
{
private:
static WindowManager* s_wndmgr; //A singleton maintains a pointer to itself as a class variable
std::vector<GUIItem*> m_guilist; //storage for gui item
//...
public:
static void Create();
static void Destroy();
static inline WindowManager* Get()
{
return s_wndmgr;
}
static void addItem(GUIItem *newGUIItem);
};
And the class:
#include "WindowManager.h"
#include "GUIButton.h"
WindowManager* WindowManager::s_wndmgr = NULL;
WindowManager::WindowManager()
{
s_wndmgr = NULL;
}
WindowManager::~WindowManager()
{
//Cleanup other stuff if necessary
delete s_wndmgr;
}
void WindowManager::Create()
{
if ( !s_wndmgr ) s_wndmgr = new WindowManager();
GUIButton *m_btn1 = new GUIButton();
addItem(m_btn1);
}
void WindowManager::Destroy()
{
if ( s_wndmgr ) delete s_wndmgr;
}
void WindowManager::addItem(GUIItem * newGUIItem)
{
m_guilist.push_back(newGUIItem);
}
Hopefully it makes some kind of sense. I'm trying to create a simple gui framework from scratch in OpenGL and this is a simple window manager. My issue is with m_guilist which should be accessible so that new GUIItems can be added to it such as happens in Create (GUIItem being a base class from which others inherit, such as GUIButton).
In this case I'm using addItem in order to append items to the list but I'm running into the a nonstatic member reference must be relative to a specific object error regarding the line inside addItem. I'm a little confused as to why this is the case. I understand that making addItem static is the reason for this error, but that was done in order for it to be called from within Create. Is there a way around this?
Sorry, this is quite the poor question and my grasp of C++ isn't great yet though I'm getting there. Any thoughts on this? Something tells me I'd be better to leave the Create function alone and create another nonstatic function to create my GUIItems and add them to the list.
addItem is a static function, which does not not operate on any instance of WindowManager. It can not access m_guilist, which is non-static without an instance.
Maybe you just want:
Get()->m_guilist.push_back(newGUIItem);
But you're starting to make the interface static, that's kind of hybrid. It's usually that addItem is non-static and you call it with the instance you acquire by WindowManager::Get().
Yet, WindowManager doesn't have inaccessible or deleted constructor to qualify as a singleton class. Ways to implement a Singleton design pattern.
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
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);
i'm sorry for the title. I seem to have a problem. I'm just a beginner and i'm sorry if this was asked before.. i couldnt find a straight answer on this one. (when i search class, pointer and child i get results about passing parent or child pointers... i do not want to pass the (this) child or parent pointer, i just want to pass a pointer i initialized on a child class.. to the parent). What i'm trying to do here is better explained by code:
class App
{
public:
virtual void init(void) { window = &BasicWindow(); }
virtual void createWindow(void) { window->create(); }
protected:
Window *window;
};
class Game : public App
{
public:
virtual void init(void) { window = &OpenGLWindow(); }
};
int main ()
{
App *game = &Game();
game->init();
game->createWindow();
return 0;
}
Is this legal?
I have an abstract Window class from which BasicWindow and OpenGLWindow derives.
However, when i create the window i get an Access violation reading location error breaking at window->create() inside the App::createWindow() function.
Thanks
I'm guessing this is because you are pointing to a temporary:
window = &BasicWindow()
Once that function exits, window points to "crap" and bad things will happen.
presumably, what you want to do is to create a new instance of the window - i.e.
window = new BasicWindow();
Don't forget to cleanup!
I'm going to take a punt that you're coming from Objective-C? ;)
I think your problems all stem from not understanding how C++ objects are created.
First up: window = &BasicWindow(); is not how you should be creating a new object. You need to use window = new BasicWindow; This results in space for a BasicWindow being allocated in memory, and the default constructor for BasicWindow will be invoked.
Your have a similar error in your main() method, however in this case you do not need to use new to allocate it, you can just declare an instance and it will be created on the stack.
Your main method would then look like:
int main ()
{
Game game;
game.createWindow();
return 0;
}
The remaining problem is that your init methods are not being called. In C++ constructors are called automatically, and are named the same name as the class. An example default constructor for the game class would be:
Game() { window = new OpenGLWindow(); }
Another thing you need to know is that, unlike objective C, the entire hierarchy of constructors is called automatically when you create an object. That is, when you create an instance of Game, its constructor is called, as well as the constructor of every base class. In fact, the base class constructor is called FIRST. So in your case, if you just change the init methods to constructors, you'll allocate two windows (one of each type) and leak the BasicWindow. Which is not cool.
You should probably just leave them named init, and just make sure you call it immediately after creation.
In summary, try this:
class App
{
public:
virtual void init(void) { window = new BasicWindow; }
virtual void createWindow(void) { window->create(); }
protected:
Window *window;
};
class Game : public App
{
public:
virtual void init(void) { window = new OpenGLWindow; }
};
int main ()
{
Game game;
game.init();
game.createWindow();
return 0;
}
(and don't forget to cleanup the new'd objects!)
EDIT (added example complete with cleanup):
class App
{
public:
App() : window( NULL ) {}
virtual ~App() { delete window; }
virtual void init() { window = new BasicWindow; }
virtual void createWindow() { window->create(); }
protected:
Window *window;
};
class Game : public App
{
public:
virtual void init() { window = new OpenGLWindow; }
};
int main ()
{
Game game;
game.init();
game.createWindow();
return 0;
}
window is an uninitialized pointer of class App. Because, no where you are calling init method. So, window->create() results error, when base class createWindow() is called.
Edit 1:
As far as now, every thing is syntactically correct but amn't sure of what you are trying to achieve. Don't create temporary/nameless objects and assign them. Instead construct them with operator new in window = &BasicWindow(); and window = &OpenGLWindow();. Since the class manages resources, you should follow the principle Rule of Three. Also know that in statement -
App *game = new Game();
The static type of operand ( App* ) is different from the dynamic type( Game*). In such a case, the static type acts as a base class and it's destructor must be virtual or else the behaviour is undefined. So, the App class destructor must be virutal.
The error might be related to the fact that you are using pointers to temporaries.
virtual void init(void) { window = &BasicWindow(); }
This pointer becomes invalid after the ";". Use "new" instead of "&".
You need to call game->init() if you want to use the window pointer too (Even better put in in a constructor, thats what they are for).
Besides that, it is perfectly legal to change protected members of base classes.
I'm not having a lot of luck in C++ getting one of my classes to see/reference/copy data from one of my other classes so it can use it.
Basically I get the error 'Core' does not name a type or when I try to forward declare (http://stackoverflow.com/questions/2133250/does-not-name-a-type-error-in-c) I get field 'core' has incomplete type
I'm guessing the second error is due to the class not really being initialized possibly, so it has nothing to get? I dunno :( (see code at the bottom)
In my C# games I would normally create a "core" class, and then within that I would start other classes such as 'entities', 'player', 'weapons', etc. When I start these other classes I would pass "this"
public WeaponManager c_WeaponManager;
...
c_WeaponManager = new WeaponManager(this);
so I could always access public values of any class from anywhere as long as it passed through core.
Eg:
So when I do my update through the 'weapon' class, and it detects its hit the player, I'd simply get a function within that class to...
core.playerClass.deductHealth(damageAmmount);
..or something like that.
It allowed me to keep lots of variables I wanted to access globally neatly tucked away in areas that I felt were appropriate.
I know this isn't a good method of programming, but its what I'm fairly comfortable with and I mainly do hobby programming so I like being able to access my data quickly without bureaucratic Get() and Set() functions handing data from one class to another and another. Also I'm still fumbling my way through header files as they seem to be a pain in the ass
//-----------[In vid_glinit.h]-------------------
include "core.h"
class Vid_glInit
{
public:
RECT glWindowRect;
Core core;
Vid_glInit();
~Vid_glInit();
void StartGl(HWND _hGameWindow, int resolutionX, int resolutionY);
private:
};
//------------[in core.h]----------
include "vid_glinit.h"
class Core
{
public:
Vid_glInit vid_glinit(this);
enum GAME_MODE
{
INIT,
MENUS,
GAMEPLAY
};
GAME_MODE gameMode;
HWND hGameWindow;
HGLRC hGameRenderContext; // Permanent Rendering Context
HDC hGameDeviceContext; // Private GDI Device Context
//functions go here
Core();
~Core();
void testFunc();
void Run();
void Update();
void Render();
void StartGl(int resoultionX, int resolutionY);
private:
};
The goal is that when I start OpenGl, instead of having lots of little functions to pass data around I simply tell the glFunctions who need the Device or Rendering context to use core.hGameDeviceContext , if that makes sense
The problem is that you've got
class Vid_glInit
{
public:
Core core;
which means allocate a full copy of the Core object inline inside this class, and also
class Core
{
public:
Vid_glInit vid_glinit(this);
which means allocate a full copy of the Vid_glInit object inline inside the class - and this is now circular, and neither structure's size can be computed.
You probably actually want to allocate at least one of them by reference or pointer, i.e.
class Core
{
public:
Vid_glInit* vid_glinit; // pointer: access properties as core.vid_glinit->foo
Vid_glInit& vid_glinit; // reference: properties are core.vid_glinit.foo
In that case you can use the class Vid_glInit; simple forward declaration because these are just pointers internally and the size of a pointer is fixed regardless of the structure behind it, i.e. C++ can lay out the Core class in memory without full knowledge of the Vid_glInit structure.