I am having trouble making a “friend” function work with a class built with wxSmith to provide a user interface for a computation-intensive statistical program. I do not want to make all of the coding of the statistical routines members of the interface class, so the natural thing to do is to create a function to write results to the interface that is globally accessible but is a “friend” of the interface class. This sounds simple, but I have been unable to do it. After much guesswork, I got a program that compiles and starts to run but crashes when the friend function is used.
The interface program, if I may call it that, is essentially that of Tutorial 9 of on-line wxSmith tutorials. I can illustrate the problem, however, with an even simpler program.
Use Code::Blocks to create a wxWidgets application called GwxAmicus. Put on the window a box sizer; in the box sizer, put a panel and mark its Expand property. Onto the panel, put another box sizer and make it vertical. Into this sizer put (1) a button with label Insider, name InsiderBtn, and proportion 0; below it put (2) a button with label Amicus, name AmicusBtn, and proportion 0; finally, in the third box, put (3) a wxTextCtrl, make the Text field blank, give it the name Results, uncheck Default size and make it 300 by 200, check the Expand property, drop down the Size property and give it the AutoScroll, Multiline, and Full_Repaint_on_Resize properties. Now double-click the Insider button and code its response like this:
void GwxAmicusFrame::OnInsiderBtnClick(wxCommandEvent& event){
Results->AppendText(_("From insider\n"));
}
Double-click the Amicus button and code its response like this:
void Amicus();
void GwxAmicusFrame::OnAmicusBtnClick(wxCommandEvent& event){
Amicus();
}
The Amicus() function is going to be a friend of the GwxAmicusFrame class, so we edit GwxAmicusMain.h by addition of one line so it begins as follows:
class GwxAmicusFrame: public wxFrame
{
public:
GwxAmicusFrame(wxWindow* parent,wxWindowID id = -1);
virtual ~GwxAmicusFrame();
friend void Amicus(); // added by me
The last line was added by me.
Now we need to write the Amicus() function. Basically, we want something like this:
void Amicus(){
xxxx->Results->AppendText(_("From Amicus\n"));
}
The first problem is what to put where I have written xxxx. We cannot just leave it blank; Amicus() is a friend but not a member of the GwxAmicusFrame class, so we need a pointer to the class, but what exactly should it be? After considerable unsuccessful guessing and producing programs which would not compile (usually producing the enigmatic error message “expected unqualified-id before -> token) I happened to look at the GwxAmicusApp.cpp file and there I saw the following:
#include "wx_pch.h"
#include "GwxAmicusApp.h"
//(*AppHeaders
#include "GwxAmicusMain.h"
#include <wx/image.h>
//*)
IMPLEMENT_APP(GwxAmicusApp);
bool GwxAmicusApp::OnInit()
{
//(*AppInitialize
bool wxsOK = true;
wxInitAllImageHandlers();
if ( wxsOK )
{
GwxAmicusFrame* Frame = new GwxAmicusFrame(0);
Frame->Show();
SetTopWindow(Frame);
}
//*)
return wxsOK;
}
This code suggested that what I wanted in place of the xxxx was Frame->. That, however, would not work as long as Frame remained a local variable inside the OnInit() function. So I modified this code as follows:
IMPLEMENT_APP(GwxAmicusApp);
GwxAmicusFrame* Frame; //Added by me
bool GwxAmicusApp::OnInit()
{
//(*AppInitialize
bool wxsOK = true;
wxInitAllImageHandlers();
if ( wxsOK )
{
GwxAmicusFrame* Frame = new GwxAmicusFrame(0);
Frame->Show();
SetTopWindow(Frame);
}
//*)
return wxsOK;
}
// Next three lines added by me:
void Amicus(){
Frame->Results->AppendText(_("From Amicus\n"));
}
At last, the program compiled, linked, and began execution. The Insider button worked perfectly. But when, full of hope, I clicked the Amicus button, it crashed and exited.
What am I doing wrong? What is the right way to deal with this problem?
Sorry to have to take so much of your time to explain the problem, but I did not want to be cryptic. Any help would be most appreciated.