Accessing member variables of MFC dialog in non-member function - c++

I'm working on a MFC dialog and I'm not sure how to access object's member variables (Edit controls, buttons, check boxes, etc) from a non-member function.
Since the object is created in whatever.cpp, and all the object events are handled in whateverDlg.cpp, and the latter #include's the former, I can't access Dlg's members by conventional means.
Example for clarification:
void BlahDlg::OnBnClickedblah()
{
//...
CString text = L"blahblahblah";
m_bEditControl.SetWindowTextW(text.GetBuffer()); //works fine
//...
}
void nonMember()
{
//...
CString text = L"blahblahblah";
m_bEditControl.SetWindowTextW(text.GetBuffer()); //m_bEditControl is unknown
//...
}
In other words: What should I do to access m_bEditControl (or any other dialog's member) from the non-member function?

If you want to keep GUI separated from logic, then you can keep your dialog class very thin, basically just for recognizing events that occur (onBtnSomethingClick, onPaint, onCancel, etc.) and create a class that will be responsible for handling these events once they occur.
One of the simplest possible solutions would be to construct this kind of class by passing your dialog by reference to its constructor:
class MyClass
{
public:
MyClass(MainDlg& dlg) : dlg_(dlg) { }
private:
MainDlg& dlg_;
};
And your dialog class could instantiate object of your class:
class MainDlg : public CDialog
{
public:
BOOL MainDlg::OnInitDialog()
{
//...
myClass_ = new MyClass(*this);
return TRUE;
}
~MainDlg()
{
//...
delete myClass_;
}
private:
MyClass* myClass_;
};
Just don't "spread" references to any GUI classes any further. If you need to directly access some members of your dialog, then you might consider redesigning your code - for example if you are writing method for creating new Users and you are thinking about accessing some text field of your dialog, then it seems to be much better idea, to "collect" input from dialog members and pass it to this kind of function independantly from your dialog class.
To your problem: if you have a helper non-member function that needs to use dialog's CEdit member, then you can change void nonMember() to void nonMember(CEdit& m_bEditControl) and pass the reference to this member when calling it in member function: nonMember(m_bEditControl); But note that that kind of approach is wrong.
In other words: this seems to be a bad design:
void nonMember(CEdit& m_bEditControl)
{
CString text = L"something";
m_bEditControl.SetWindowTextW(text.GetBuffer());
}
void MainDlg::someMethod()
{
nonMember(m_bEditControl);
}
and this seems to be much better:
CString nonMember2()
{
return L"something";
}
void MainDlg::someMethod()
{
CString str = nonMember2();
m_bEditControl.SetWindowTextW(str.GetBuffer());
}
Hope this helps :)

Related

Function pointer, Functor or Lambda?

I'm relatively new to C++, having spent years with Obj-C, and wondering about how to add what would be closure block in Obj-C, to a C++ class. Here's some pseudo code of what I want to do:
class Slider
{
public:
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
if(myFunctionPointer != nil)
{
// show popup menu
myFunctionPointer(this);
}
}
}
FunctionPointer myFunctionPointer = nil;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider;
mySlider->functionPointer = showPopupMenu();
}
Slider *mySlider;
};
As you can see, I'm trying to get my Slider class to call a function without knowing anything about it.
This shouldn't be that difficult, but I'm interested in doing it the best/proper way. Lambdas and functors look incredibly confusing. Maybe I'm looking for something else. But what?
When it comes to treating function as objects, your basic options are: function pointer, functor/lambda, std::function. I am going to assume that you can find out their syntax and will focus on their difference.
A function pointer should be used when there is no need for a closure. This applies when the procedure you want to call is stateless or has a global state, and you have all parameters in the scope.
A functor should be used when you need to create a closure. Since functors are objects, you can maintain an internal state and pass parameters inside the closure.
A lambda is essentially a functor, without an explicit typename. The capture list of a lambda is its member if it were implemented as a functor instead. Note that you can overload operator() for a functor but not a lambda.
The problem with functor/lambdas is that each of their definition has a different type, and can be ill-suited in function signature/class member types. std::function resolves the problem by being able to accept functor/lambda/function pointer and convert them to a uniform type of std::function. You pay a (often small) price for this flexibility in the form of performance though.
Lambdas and functors are one of the most advanced C++ topics. You're better off starting with some fundamentals before, and have a solid understanding of how C++ classes work.
But, since you asked, the C++ equivalent of this should be something like this:
class Slider
{
public:
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
if(myFunctionPointer)
{
// show popup menu
myFunctionPointer(this);
}
}
}
std::function<void (Slider *)> myFunctionPointer=nullptr;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider;
mySlider->functionPointer = [this](Slider *)
{
showPopupMenu();
};
}
Slider *mySlider;
};
As I said, I think that you're better off focusing your efforts on getting the fundamentals down pat, first, before plunging into these shark-infested waters.
And just to add some additional color: this will compile (the only thing that's missing is the definitions of rightClick or ctlKeyDown), but it may or may not be right, depending on the scope and the lifetime of the objects involved. It may or may not be necessary to have the lambda capture a std::shared_ptr, instead of this, depending on how the objects in this application get instantiated. Understanding how C++ objects work would be a necessary prerequisite before dealing with closures and callbacks, of this sort.
There are different ways to achieve what you're looking for.
Here's a way, avoiding function pointers.
I didn't correct some other obvious mistakes, like the memory leak that arises from callingnew and never deleting the object.
Best practice in this case would be using a std::unique_ptr
class Slider
{
public:
Slider(Editor& e)
: _e(e)
{ }
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
_e.showPopupMenu(this);
}
}
Editor& _e;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider(*this);
}
Slider* mySlider;
};
Here's another solution moving a functor directly in the constructor, however using templates.
template <typename Handler>
class Slider
{
public:
Slider(Handler&& h)
: _h(std::move(h))
{ }
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
// show popup menu
_h(this);
}
}
Handler _h;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider([this](Slider* s){ showPopupMenu(s); });
}
Slider *mySlider;
};
You could also use a std::function instead, as shows on another answer

Passing QObject with Pointer (Qt)

My goal is to pass the windowobject pointer to another class.
I'll show you what i got so far.
where: "dialog" is the window to pass.
mainwindow.cpp
dialog = new Dialog(this);
someClass(dialog);
Konstruktor in someClass
someClass::someClass(Dialog *d)
{
Dialog *dia = d;
}
someClass.h
#include "dialog.h"
...
public:
someClass(Dialog *dialog)
//Dialog d;
The program runs now, but i'm not sure if i achieved what i wanted.
Is it possible to interact with my dialog now?
What i want is something like this.
dia->ui->lineEdit->setText();
Any help would be appriciated
someClass(&dialog);
is incorrect ... you have a pointer and give the address of the pointer (a pointer to the pointer) in the function
also you have
Dialog d;
in your header and assigning a Dialog* to it.
I recommend you to have a look at: The Definitive C++ Book Guide and List
My goal is to pass the windowobject pointer to another class. I'll
show you what i got so far. where: "dialog" is the window to pass.
considering your code:
someClass::someClass(Dialog *d)
{
Dialog *dia = d;
}
is a local member in the constructor someClass. Therefore it only has scope in the constructor itself (is not visible outside of the constructor, and in fact, does not live outside of the constructor (is destroyed when the constructor goes out of scope)).
Fortunately dia is a pointer (address of object), and not the actual dialog (therefore only the pointer, and not the object that it points to goes out of scope). If you want the pointer to remain in scope for the purpose of access later on, you have to "tie" it to the scope of the class (make it a class member).
class MyClass
{
public:
//Using reference as it may not be null...
MyClass( Dialog& dialog );
void showDialog();
private:
//We only want to expose a small part of dialog to users,
// hence keep it private, and expose what we want through
// the interface (the public part).
Dialog& dialog_;
};
//MyClass.cpp
MyClass::MyClass( QPointer<Dialog> )
: dialog_( dialog ) //Google "member initialisation"
{
}
void MyClass::showDialog(){ dialog_.show(); }
----- Modified/Additional answer -----
If in the above example dialog_ is optional, then you needn't make it a reference member, as reference members require to be initialised (one cannot have an uninitialised reference). In that case, make it a pointer... When using Qt, I would make it a QPointer (Assuming Dialog is a QObject), as QPointers are safer to work with than raw pointers (They are always initialised to zero, at least).
I'll show you the basic principle to keep it simple for now. Read up about QPointers and smart pointers in general.
e.g:
class MyClass
{
public:
// May or may not hold zero...
explicit MyClass( Dialog* dialog = 0 );
void showDialog();
private:
//We only want to expose a small part of dialog to users,
// hence keep it private, and expose what we want through
// the interface (the public part).
Dialog* dialog_;
};
//.cpp
MyClass::MyClass( Dialog* dialog /* = 0*/ )
: dialog_( dialog )
{
}
void MyClass::showDialog()
{
if( dialog_ )
{
dialog_->show();
}
else
{
std::cout << "This is in fact not a dialog"
"\nbut be so kind as to enter"
" whatever you want here ;-)"
<< std::endl;
while( !terminated() )
{
std::string inputStr;
std::cin >> inputStr;
evalute( inputStr );
}
}
}
We don't know what your Dialog class looks like, but if its member ui is public (or someClass is a friend of Dialog), then you should be able to do
dia->ui->lineEdit->setText();
Do you get any compiler errors? Or does the text simply not show up as expected?
You would still need to show the dialog at some point using
dia->show();
or
dia->exec();

A dependency loop

I've designed an object inherits from CDialog (called NBDialog, and some derived objects of controls, such as CEdit, CDateTimeCtrl, CComboBox etc.
The NBDialog is one project, and the controls are in other projects.
Naturally, All of the controls are put on the dialog and use dialog's methods, so I have to
#include NBDialog.h, and to add its .lib file for the linker.
I also want to handle all those controls from the dialog, so I wrote in NBDialog.h the following lines:
class NBCommonEditBox;
class NBDateTimeCtrl;
class NBCommonComboBox;
CMapWordToOb* NBGetEditBoxMap();
NBCommonEditBox* NBGetEditBoxById(unsigned long ID);
CMapWordToOb* NBGetDateTimeMap();
NBDateTimeCtrl* NBGetDateTimeById(unsigned long ID);
CMapWordToOb* NBGetComboBoxMap();
NBCommonComboBox* NBGetComboBoxById(unsigned long ID);
This way NBDialog.h doesn't know the context of the object, but it knows they are exist and stores them in the maps.
Now I want to extend the NBDialog project and add a method which will get the print information of all controls, so all objects which inhertied from NBDialog will be able to use this method. The print information is defined in the controls implementation.
EDIT: If I write this method in NBDialog.cpp, I can't compile it, because NBDialog doesn't know the context of the controls' classes:
CStringList* NBDialog::NBGetMainTexts()
{
CStringList* mainTexts = new CStringList();
POSITION pos;
WORD key;
NBCommonEditBox* currEdit = NULL;
for (pos = this->NBGetEditBoxMap()->GetStartPosition(); pos != NULL;)
{
this->NBGetEditBoxMap()->GetNextAssoc(pos, key, (CObject*&)currEdit);
currEdit->NBStringsToPrint(mainTexts);
}
return mainTexts;
}
Is there a way to write the desired method?
Easiest way is to define an interface for this and add that interface instead of the CObject. The interface can offer a method to get hold of the control itself. Don;t be afraid of multiple inheritance - yes it can have a slight performance penalty but it is not going to be an issue for you. In this case it will be similar to interface inheritance in Java since you would use a pure interface.
You could also implement this in a similar way that avoids multiple inheritance but it adds more complexity that you don't need.
// Interface goes in the NBDialog project
class INBControl {
public:
virtual ~INBControl() = 0;
virtual CWnd* getWnd() = 0;
virtual void getStringsToPrint(CStringList& strings) = 0;
};
inline INBControl::~INBControl() {}
class NBCommonComboBox : public CComboBox, public INBControl
{
public:
// ... stuff ...
virtual CWnd* getWnd() {
return this;
}
virtual void getStringsToPrint(CStringList& strings) {
strings.AddTail("foo"); // for example
}
};
// NBDialog
#include <map>
class NBDialog : public CDialog
{
public:
// .. stuff ..
private:
typedef std::map<int, INBControl*> ControlMap;
ControlMap control_map_;
};
void NBDialog::addNBControl(INBControl* control, int id)
{
CWnd* wnd = control->getWnd();
// Do stuff with the control such as add it
control_map_[id] = control;
}
// let the caller be responsible for [de]allocation of the string list
void NBDialog::NBGetMainTexts(CStringList& texts)
{
ControlMap::iterator i = control_map_.begin();
ControlMap::iterator e = control_map_.end();
for(; i != e; ++i) {
i->second->getStringsToPrint(texts);
}
}
Alternatively use a custom windows message and iterate all the controls, down-casting to CWnd and using SendMessage on its HWND. Each control will need to handle your custom windoes mesaage. You could pass a pointer to the string list in the LPARAM of the message. This apprach is flexible but somewhat brittle/unsafe and could crash if you end up using the same message ID for something else by accident.
Your implementation file (NBDialog.cpp) is free to #include the necessary headers to make this work (presumably things like NBCommonComboBox.h, etc.) Because the .cpp file isn't #include'd by anything you won't cause any circular include problems.

Function pointer to a non-static member function when the class type is unknown?

I'm working on a game project that features scratch-built controls rendered into an opengl context; things like buttons, scrollbars, listboxes, etc. Many of these controls are nested; for example, my listbox has a scrollbar, a scrollbar has 3 buttons, etc.
When a scrollbar changes value, I'd like it to call 'some' function (typically in it's parent object) that responds to the change. For example, if the listbox has a slider, it should instantiate the slider, then tell the new slider that it should call the listboxes 'onScroll(float)' function. All of the controls share a common base class, so I could have a 'base* parent' parent pointer, then do 'parent->onScroll(val)'. The problem though is what happens when the parent doesn't inheirit from base; there'd be no virtual onScroll() to follow through, so the top-level parent would have to periodically check to see if any of the child controls had changed value. This would also clutter up other controls, since they may not even have children, or may require different event types like when a list entry object is selected, etc.
A better solution would be to have the child object maintain a generic function pointer (like a callback), which can be set by the parent, and called by the child as necessary. Something like this:
typedef (*ptFuncF)(float);
class glBase {
public:
//position,isVisible,virtual mouseDown(x,y),etc
};
class glDerivedChild : public glBase {
public:
glDerivedChild();
~glDerivedChild();
void changeValue(float fIn) {
Value = fIn; //ignore these forward declaration errors
(*callBack)(fIn);
}
void setCallBack(ptFuncF pIn) {callBack = pIn;}
ptFuncF callBack;
float Value;
};
class glDerivedParent : public glBase {
public:
glDerivedParent() {
child = new glDerivedChild();
child->setCallBack(&onScroll);
}
~glDerivedParent() {delete child;}
void onScroll(float fIn) {
//do something
}
glDerivedChild* child;
};
class someFoo {
public:
someFoo() {
child->setCallBack(&setValue);
}
void setValue(float fIn) {
//do something else
}
glDerivedChild child;
};
I'm kinda new to function pointers, so I know I'm (obviously) doing many things wrong. I suspect it might involve something like "typedef (glBase::*ptFuncF)(float);" with the 'onScroll(f)' being an overridden virtual function, perhaps with a generic name like 'virtual void childCallBack(float)'. I'd prefer to keep the solution as close to vanilla as possible, so I want to avoid external libraries like boost. I've been scratching my head over this one for the better part of 8 hours, and I'm hoping someone can help. Thanks!
I think, what you want is some kind of events or signals mechanism.
You can study, how event processing is organized on Windows, for example. In short, your scrollbar generates new event in the system and then system propagates it to all elements, registered in the system.
More convenient mechanism is signal/slot mechanism. Boost or Qt provides such tools. I'll recomend this solution.
But if you still want to use just callbacks, I'll recommend using std::function (boost::function) (combined with std::bind (boost::bind), when required) instead of raw function pointers.
Use boost::function (or std::function if available). Like this (using your notation):
typedef std::function<void (float)> ptFuncF;
//...
void setCallBack(const ptFuncF &pIn);
//...
child->setCallBack(std::bind(&glDerivedParent::onScroll, this, _1));
//...
child->setCallBack(std::bind(&someFoo::setValue, this, _1));
A function pointer to a member function of a class has such a type:
<return type> (<class name>::*)(<arguments>)
For example:
typedef void (glBase::*ptFuncF)(float);
^^^^
by the way, you have forgot the `void` in your `typedef`
ptFuncF func = &glDerivedChild::onScroll;
And you use it like this:
glDerivedChild c;
(c.*func)(1.2);
In your particular example, the function is a member of the derived class itself, therefore you should call it like this:
(c.*c.callback)(1.2);
the inner c.callback is the function pointer. The rest is exactly as above, which is:
(class_instance.*function_pointer)(arguments);
You might want to take a look at this question also.
Ok, the workaround I came up with has some extra overhead and branching, but is otherwise reasonable.
Basically, each callback function is implemented as a virtual member function that recieves the needed parameters including a void* pointer to the object that made the call. Each derived object also has a base-class pointer that refers to the object that should recieve any events that it emits (typically its parent, but could be any object that inheirits from the base class). In case the control has multiple children, the callback function uses the void* pointer to distinguish between them. Here's an example:
class glBase {
public:
virtual onChildCallback(float fIn, void* caller);
glBase* parent;
};
class glSlider : public glBase {
public:
glSlider(glBase* parentIn);
void changeValue(float fIn) {
Value = fIn;
parent->onChildCallback(fIn, this);
}
float Value;
};
class glButton : public glBase {
public:
glButton(glBase* parentIn);
void onClick() {
parent->onChildCallback(0, this);
}
};
class glParent : public glBase {
public:
glParent(glBase* parentIn) : parent(parentIn) {
childA = new glSlider(this);
childB = new glButton(this);
}
void onChildCallback(float fIn, void* caller) {
if (caller == childA) {
//slider specific actions
} else if (caller == childB) {
//button specific actions
} else {
//generic actions
}
}
glSlider* childA;
glButton* childB;
};
Besides a reasonably small amount of overhead, the scheme is flexible enough that derived classes can ignore certain components or omit them altogether. I may go back to the function pointer idea later (thanks shahbaz), but half the infrastructure is the same for both schemes anyway and the extra overhead is minimal, especially since the number and variety of controls will be rather small. Having the callback function use a nested response is actually a little better since you don't need a separate function for each child object (eg onUpButton, onDownButton, etc).

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.