Passing class pointer to a function - c++

I want to use different WText instances in another function, but as I want to have just one control function, I'd like to pass them in there.
The code with current setup compiles but fails due to some memory fault which I don't understand.
class mode : public WApplication
{
//..
private:
//..
void someFunc();
void control(WText* texty);
WText* text;
WText* text2;
WText* text3;
//...etc
};
void mode::someFunc(){
control(text); //how to pass it?
//might pass text2 or text3 as well
}
void mode::control(WText* texty){
texty->setText("blabla");
//..
}

text member is a pointer to the object WText,
The first thing you need to do is a create a new WText object:
void mode::someFunc() {
text = new WText();
control(text);
}
please remember about destroy text object after use.

Related

Passing vector by reference to another class/file

I have 2 sets of header+source files. One with the Main GUI class and the other with a Derived GUI class (Main window that opens a second window).
In the Main class I have a vector of strings. I can pass that vector by reference by calling a function in the Derived class and pass it by reference. I can use and update that vector in this function and the changes will be available in the Main class/file. So far so good.
The next thing I would like to do is use this passed by reference vector in all functions in the Derived class.
Up to now, I created and 'extern' vector in a "common" set of header+source.
This make it a global vector, and although its working, it is not the most elegant way.
Is there an alternative way to make the vector available to all functions in the Derived GUI class/file (and add/edit elements that are available in the Main GUI class/file later on)?
MainFrame.h
class wxMainFrame: public GUIFrame
{
public:
wxMainFrame(wxFrame *frame);
~wxMainFrame();
DerivedFrame *m_DerivedFrame;
private:
std::vector<wxString> vwsM3;
....etc
}
DerivedFrame.h
class DerivedFrame: public OtherFrane
{
public:
DerivedFrame( wxWindow* parent );
~DerivedFrame();
private:
std::vector<wxString> vwsM4;
void PassVector(std::vector<wxString> &vwsM);
void USEvwsM();
....etc
}
MainFrame.cpp
wxMainFrame::wxMainFrame(wxFrame *frame) : GUIFrame(frame)
{
m_DerivedFrame = new DerivedFrame(this);
m_DerivedFrame->PassVector(&vwsM3);
}
DerivedFrame.cpp
DerivedFrame::DerivedFrame ( wxWindow* parent ) : OtherFrame( parent )
{
//
}
void DerivedFrame::PassVector(std::vector<wxString> &vwsM)
{
vwsM.push_back("Something");
}
void USEvwsM()
{
// ??
}
OnInit() (The vector vwsM3 is not known here because its in a seperate header+source file)
IMPLEMENT_APP(wxMainApp);
bool wxMainApp::OnInit()
{
wxMainFrame* frame = new wxMainFrame(0L);
frame->SetIcon(wxICON(aaaa)); // To Set App Icon
frame->Show();
return true;
}
To derived class add one more pointer field:
class DerivedFrame: public OtherFrame {
.......
private:
std::vector<wxString> * pvwsM3 = nullptr;
.......
};
Modify PassVector() method to fill pointer:
void DerivedFrame::PassVector(std::vector<wxString> & vwsM) {
pvwsM3 = &vwsM;
}
Use pointer now:
void DerivedFrame::USEvwsM() {
assert(pvwsM3); // Check that we don't have null pointer, you may throw exception instead.
pvwsM3->push_back("Something");
}
Remaining code is same as you have. Alternatively you may pass vector to constructor of DerivedFrame, which is more reliable than calling PassVector() separately (which you may forget to call, while constructor you always call):
DerivedFrame::DerivedFrame(wxWindow* parent, std::vector<wxString> & vwsM)
: OtherFrame( parent ) {
this->PassVector(vwsM);
}
If you pass vector of strings to constructor only then you don't need a pointer, but reference in derived class, so instead of pointer field
class DerivedFrame: public OtherFrame {
std::vector<wxString> * pvwsM3 = nullptr;
.......
};
make reference field
class DerivedFrame: public OtherFrame {
std::vector<wxString> & rvwsM3;
.......
};
then remove PassVector() method and add reference initialization in constructor:
DerivedFrame::DerivedFrame(wxWindow* parent, std::vector<wxString> & vwsM)
: OtherFrame( parent ), rvwsM3(vwsM) {}
and use it as a reference (unlike pointer reference doesn't need to be checked for null):
void DerivedFrame::USEvwsM() {
rvwsM3.push_back("Something");
}
Reference compared to pointer has two advantages - it can't be forgotten to be initialized, because with reference you don't need to call PassVector(), and you don't need to check if it is null unlike checking pointer (reference is never null). But reference can be initialized only in constructor, while pointer can be initialized later, far later after object was constructed.
Having a global vector is bad practice, but anyhow typical for a settings like vector.
When I understand right, the vector you want to share, is known in the base like this
struct base {
std::vector<std::string>& data;
base(std::vector<std::string>& init) : data(init) {}
};
struct derived : base {
derived(std::vector<std::string>& init) : base(init) {}
void have_fun_with_VectorOfStrings();
};
it can be directly accessed in derived class, or any entity having access to one of the derived class.
Not sure if you might be looking for a different approach like the singleton pattern instead:
class coolStuff {
public:
std::vector<std::string> data;
static coolStuff& get() {
static coolStuff instance;
return instance;
}
private:
coolStuff () {
// constructor called once using "get", so can be used for initialization
}
};
This would be simply called anywhere you need it. Since only 1 instance exists, it might be a better approach to achieve the same.
coolStuff::get().data.push_back("add a new string");
You have shared a code example meanwhile, so your example would look like this applying approach 1 above.
class wxMainFrame: public GUIFrame {
public:
wxMainFrame(wxFrame *frame, std::vector<wxString>& vwsM3);
private:
std::vector<wxString>& vwsM3;
};
wxServerFrame::wxServerFrame(wxFrame *frame, std::vector<wxString>& _vwsM3) : GUIFrame(frame)
, vwsM3(_vwsM3)
{
m_DerivedFrame = new DerivedFrame(this, _vwsM3);
// m_DerivedFrame->PassVector(&vwsM3); // not needed anymore
}
// same for further inherited classes
If I may add a side note: It looks like you are doing some graphic-like stuff, so performance should be considered aswell: Try to avoid dynamic allocations like new, mallcoc, etc, since this is a very slow operation. An optimization might be to use a member in the class, instead of allocating to a member pointer at runtime.

C++ can't access field from inherited class

Hello guys a have a problem, that i can't access field tablica[i]->help, in generuj function, its saying that this field is not existing in class Task.
How can i achieve it ?
class Task
{
protected:
string contents;
int id_pyt;
int nr_pyt;
};
class Task4Answ : public Task
{
private:
int help;
public:
Task4Answ(string contents1, int id,int nr,int help1)
{
contents=contents1;
id_pyt=id;
nr_pyt=nr;
help=help1;
}
};
class TaskCollection
{
protected:
Task *collection[60];
public:
friend class Generator;
TaskCollection()
{
collection[0] = new Task4Answ("Ile jest por roku w Polsce? \na) 1 \nb) 2 \nc) 3 \nd) 4",1,0);
collection[1] = new Task4Answ("Kto wygral tegoroczny Roland Garros? \na) Federer \nb) Djokovic \nc) Nadal \nd) Thiem",1,1);
class Generator
{
protected:
Task *tablica[10];
TaskCollection T1;
public:
Generator(){}
void Generuj()
{
if(T1.collection[x]->id_pyt==1)
{
tablica[i]=new Task4Answ("0",0,0);
tablica[i]->contents=T1.collection[x]->contents;
tablica[i]->id_pyt=T1.collection[x]->id_pyt;
tablica[i]->nr_pyt=T1.collection[x]->nr_pyt;
tablica[i]->help=T1.collection[x]->help; //here is the problem
}
}
}
Or maybe there is some other solution of the project im doing now.
Thanks for any help.
The problem is in this line:
tablica[i]=new Task4Answ("0",0,0);
Although you have called the Task4Answ constructor, you are also assigning the memory address returned by new to a Task pointer. Effectively, you have casted the Task4Answ pointer to a Task pointer. On the lines that follow, C++ only sees tablica[i] as a reference to a Task pointer. You need to change:
protected:
Task *tablica[10];
TaskCollection T1;
...to this:
protected:
Task4Answ *tablica[10]; // Task was changed to Task4Answ
TaskCollection T1;
That should allow C++ to see tablica as an array of Task4Answ pointers instead of Task pointers.
Edit: it looks like help is also private. You will have to change help to public or add TaskCollection::TaskCollection() as a friend. Otherwise, C++ will not let you get or set help.
Edit: the OP added that tablica[i] might contain instances of other classes that inherit from Task. In that case, you could do something like this:
void Generuj()
{
if(T1.collection[x]->id_pyt==1)
{
Task4Answ* newTask = new Task4Answ("0",0,0);
newTask->contents=T1.collection[x]->contents;
newTask->id_pyt=T1.collection[x]->id_pyt;
newTask->nr_pyt=T1.collection[x]->nr_pyt;
newTask->help=T1.collection[x]->help; // You will still have to change this from being private.
tablica[i] = newTask;
}
}
}
Later on, in order to access help, you will need to implement some sort of way of checking whether tablica[i] is a Task4Answ and not an instance of some other class that inherits from Task, perhaps by implementing a method in Task named IsTask4Answ that returns false in Task but is overridden to return True in Task4Answ. You can then cast the pointer back to Task4Answ with something like the static_cast operator. In other words:
// Add these functions to the class definitions:
virtual bool Task::IsTask4Answ() const {
return false;
}
bool Task4Answ::IsTask4Answ() const override {
return true;
}
// Later, you can do this:
if(tablica[i].IsTask4Answ()){
Task4Answ* t = static_cast<Task4Answ*>(tablica[i]);
t->help; // Again, you'll have to change this from being private.
}
Although I suggest figuring out a different data structure where you do not need to do any casting, this will allow you to access help.
Do note the virtual keyword in the first function above; it allows the function to be dynamically bound, which means that the code will check whether to call Task::IsTask4Answ() or Task4Answ::IsTask4Answ() at runtime instead of at compile time.

C++ Calling a getter method when it is not ready

I'm working on a project and it works but it is really messy so I am trying to clean it up by moving things around.
Here is a short version of the class containing the getter method
Link::Link
{
jsonUrl = QUrl("www.example.json");
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(downloadFinished(QNetworkReply*)));
QNetworkRequest request(jsonUrl);
nam->get(request)
}
void Link::downloadFinished(QNetworkReply *reply)
{
jsonArray = reply->readAll();
jsonStuff();
}
void Link::jsonStuff()
{
//does a bunch of json stuff then gets a string
string = map["url"].toString();
}
QString Link::getString()
{
return string;
}
Here is a short version of the class that calls the getter in the constructor
Header
class Commands
{
private:
Link link;
}
Source inside the constructor
Commands::Commands()
{
addCommand("!test", link.getString());
}
The problem is when I try to do it like this, I think the Commands constructor runs first and the string from the Link class is not ready yet so the string that comes out of link.getString() is empty. Is there a way to wait until the Link class finishes doing it's stuff and fills up the string before calling link.getString() inside the constructor of Commands? Not sure if this matters but most of my code is written in Qt
I hope you guys can understand what I'm trying to ask. My terminology is really poor.
Edit: Added more to my Link class
When the constructor of Commands (in this case Commands()) is called firstly it creates all variables(they are unintialized) in Commands class. That being said link is created via Link(). What you might want to do is to use jsonStuff() in the Link() constructor (it creates all member variables as well as), NOTE THAT it creates variables in this case it creates string with base costructor - it creates empty string.) Try following to fill the string:
Link() {
jsonStuff(); // string will be set
}
Or you can initialize it via initialization section:
Link() : string("Text") { }
Also you might want to return reference to string from getString() function. Reference means it doesn't create additional copy and it returns string which is stored in Link, so you can change string in a function where getString() is called. Also if it is read only you should use const reference.
Is there a way to wait until the Link class finishes doing it's stuff and fills up the string before calling link.getString() inside the constructor of Commands?
Certainly. The Link class must be a QObject that emits a signal when it has changed its properties - presumably based on the replies it got to its network request.
class Link : public QObject {
Q_OBJECT
Q_PROPERTY(QString string READ string WRITE setString NOTIFY stringChanged)
QString m_string;
public:
void jsonStuff() {
...
connect(reply, &QNetworkReply::finished, this, [this]{
...
setString(map["url"].toString());
});
}
void setString(const QString &s) {
if (m_string == s) return;
m_string = s;
emit stringChanged(m_string);
}
QString string() const { return m_string; }
Q_SIGNAL void stringChanged(const QString &);
};
You can then add the command when the link is ready:
Commands::Commands()
{
connect(&link, &Link::stringChanged, this, [this](const QString &string){
if (!string.isEmpty()) addCommand("!test", string);
});
}

Is this the correct way to assign a pointer to an object into a function?

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.

c++ Setting a pointer variable in parent class from child and use it in parent class

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.