I seem to have found a case where I should be suffering from the "dreaded" diamond inheritance problem. However, the code appears to work just fine. What I can't seem to figure out for sure is if there could be a problem.
Here is the setup. I am using MFC and have extended CEdit to add custom handling of a mouse click windows message. I then inherit from this class and a class written by a third party developer (call him Bob for this example). Doing this, I can now return either my special control or an enhanced version of Bob's control. Problem is, Bob's library can not be modified and both our code ultimately inherits from CEdit (and CWnd for that matter).
Example code:
class A : public CEdit {...} // From Bob's library
class B : public A {...} // From Bob's library
class BobsEdit : public B {...} // From Bob's library
// My version which handles WM_LBUTTONDOWN, WM_CREATE
// and does a couple other cool things.
class MyEdit : public CEdit
{
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if ( !CEdit::Create(...) ) return -1;
...set some style stuff...
}
afx_msg void OnLButtonDown(UINT nFlags,CPoint point) {} // Override CWnd handler
}
class MyBobsEdit : public BobsEdit, public MyEdit {} // My version of Bob's control
// CBobsUser returns just a standard CEdit and BobsEdit control
// This is also from Bob's library.
class CBobsUser
{
CWnd* GetMeAnEditBox()
{
CEdit* pEdit;
if ( ...some condition... )
pEdit = new CEdit();
else
pEdit = new BobsEdit();
...
return pEdit;
}
}
// CMyUser overrides Bob's GetMeAnEditBox and returns
// one of my custom controls (with the new cool handler).
class CMyUser : public CBobsUser
{
...
CWnd* GetMeAnEditBox()
{
MyEdit* pEdit;
if ( ...some condition... )
pEdit = new MyEdit();
else
pEdit = new MyBobsEdit();
...
return pEdit;
}
}
So... Questions are:
Why does this not seem to suffer from the diamond inheritance problem?
Is there an issue I don't see with this design that could bite me in the future?
Is there another way to fix this if I can't modify code on one side of the diamond (i.e. I can't declare CEdit virtual on both sides? )
Thanks!
Ad 1: Because nothing ever knows the object is CBobsEdit. You create the object as MyBobsEdit, but immediately cast it to MyEdit, so all method calls are on MyEdit and no abiguous call errors arise and the cast itself is not ambiguous either. No functionality of CBobsEdit is ever used (you don't have any methods in the subclass). It is constructed, but it is never added to a parent, so it's never shown and never used.
Ad 2: Well, you are not using BobsEdit at all. Which, I suppose, is not what you wanted.
Ad 3: You can make MyEdit a template that is inherited from it's template argument and inherit it directly from CEdit in one case and from CBobsEdit in the other case. This technique is often called "mixin". Like:
template <typename BaseEditT>
class MyEdit : public BaseEditT { ... }
Unfortunately MyEdit<CEdit> and MyEdit<CBobsEdit> are unrelated classes. If you can do with storing the pointer as CEdit (which is always a base class), you'll have to define an interface, implement this interface in MyEdit and store pointer to that interface. The interface will need to contain a cast-operator to CEdit& (and CEdit const&) and than you should be able to call any CEdit methods on it. Like this:
class IMyEdit {
virtual operator CEdit &() = 0;
virtual operator CEdit const &() const = 0;
};
template <typename BaseEditT>
class MyEdit : public BaseEditT {
operator CEdit &() { return *this; }
operator CEdit const &() const { return *this; }
};
Note, that than only the code constructing the objects will need to see definition of the MyEdit template, so you can put it in a separate file and include it only where you define CMyUser constructor to avoid the penalty on compile-time.
Related
I'm learning C++ by programming a game. I'm using SDL to display my objects and a factory structure to keep it all organised.
I separated the first object (a car), the controls (keyboard) and the display (monitor).
In my main class I call the monitor class to display a window where I should draw the images. If a key is pressed, the car should react to that by redrawing the image.
The problem here is that I initialized the monitor in the main class and I can't access it in my car class..
I tried a variety of things, but nothing seems to do the trick.
So here is the main class
Game::Game(GuiFactory* factory) {
bool is_running = true;
Car* car = factory->createCar();
car->drawCar();
// create factory specific window
Monitor* monitor = factory->createMonitor();
// create factory specific keyboard
Keyboard* keyboard = factory->createKeyboard();
while (is_running) {
// keyboard input
string key_input = keyboard->getKeys();
if (key_input == "quit") {
is_running = false;
} else if (key_input != "") {
if(key_input == "right"){
car->turnRight(monitor);
}
}
}
}
I have a main car class and an SDLCar class, which inherits car.
class Car {
public:
Car();
virtual ~Car();
virtual void drawCar() = 0;
virtual void turnRight() = 0;
};
Here is where I'm confused:
class SDLCar : public Car {
public:
SDLCar();
virtual ~SDLCar();
void drawCar();
void turnRight(SDLMonitor& monitor);
// ^^^^^^^^^^^^^^^^^^^
};
Could someone please explain?
In your base class Car you have declared the method turnRight which takes no parameters.
In your derived class SDLCar you have declared a completely different method with the same name. The reason why it's a different method and not a function override is that its takes a parameter. It should be parameterless to override Car::turnRight.
And because it's not a function override, the rules of polymorphism don't apply. Thus you can't call SDLCar::turnRight(SDLMonitor&) from a Car pointer.
Right now is an excellent time to start using the override keyword. It prevents specifically these kind of programming errors. By marking a function with override:
void turnRight(SDLMonitor& monitor) override;
the compiler will automatically check that it actually overrides a function from the base class.
E.g. with the above declaration, the compiler would give you an error (or a warning at least). This would've helped you find your error right away and prevented more erroneous code such as car->turnRight(monitor).
So now that the error is found, you need to find a way to fix it. Either declare the base class turnRight to take a SDLMonitor& as well, or think of something else if that's not how it should behave.
IMO having to pass the game window to a method like turnRight seems weird. Why would turning a car need a window? I think turnRight should do just what it says on the tin: turn the car right. Nothing else.
I don't know why you're passing a window to the method but if it's for drawing, shouldn't the drawCar method handle that? I don't know your code, so I'll leave it up to you.
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.
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 :)
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).
I feel like the answer to this question is really simple, but I really am having trouble finding it. So here goes:
Suppose you have the following classes:
class Base;
class Child : public Base;
class Displayer
{
public:
Displayer(Base* element);
Displayer(Child* element);
}
Additionally, I have a Base* object which might point to either an instance of the class Base or an instance of the class Child.
Now I want to create a Displayer based on the element pointed to by object, however, I want to pick the right version of the constructor. As I currently have it, this would accomplish just that (I am being a bit fuzzy with my C++ here, but I think this the clearest way)
object->createDisplayer();
virtual void Base::createDisplayer()
{
new Displayer(this);
}
virtual void Child::createDisplayer()
{
new Displayer(this);
}
This works, however, there is a problem with this:
Base and Child are part of the application system, while Displayer is part of the GUI system. I want to build the GUI system independently of the Application system, so that it is easy to replace the GUI. This means that Base and Child should not know about Displayer. However, I do not know how I can achieve this without letting the Application classes know about the GUI.
Am I missing something very obvious or am I trying something that is not possible?
Edit: I missed a part of the problem in my original question. This is all happening quite deep in the GUI code, providing functionality that is unique to this one GUI. This means that I want the Base and Child classes not to know about the call at all - not just hide from them to what the call is
It seems a classic scenario for double dispatch. The only way to avoid the double dispatch is switching over types (if( typeid(*object) == typeid(base) ) ...) which you should avoid.
What you can do is to make the callback mechanism generic, so that the application doesn't have to know of the GUI:
class app_callback {
public:
// sprinkle const where appropriate...
virtual void call(base&) = 0;
virtual void call(derived&) = 0;
};
class Base {
public:
virtual void call_me_back(app_callback& cb) {cb.call(*this);}
};
class Child : public Base {
public:
virtual void call_me_back(app_callback& cb) {cb.call(*this);}
};
You could then use this machinery like this:
class display_callback : public app_callback {
public:
// sprinkle const where appropriate...
virtual void call(base& obj) { displayer = new Displayer(obj); }
virtual void call(derived& obj) { displayer = new Displayer(obj); }
Displayer* displayer;
};
Displayer* create_displayer(Base& obj)
{
display_callback dcb;
obj.call_me_back(dcb);
return dcb.displayer;
}
You will have to have one app_callback::call() function for each class in the hierarchy and you will have to add one to each callback every time you add a class to the hierarchy.
Since in your case calling with just a base& is possible, too, the compiler won't throw an error when you forget to overload one of these functions in a callback class. It will simply call the one taking a base&. That's bad.
If you want, you could move the identical code of call_me_back() for each class into a privately inherited class template using the CRTP. But if you just have half a dozen classes it doesn't really add all that much clarity and it requires readers to understand the CRTP.
Have the application set a factory interface on the system code. Here's a hacked up way to do this. Obviously, apply this changes to your own preferences and coding standards. In some places, I'm inlining the functions in the class declaration - only for brevity.
// PLATFORM CODE
// platformcode.h - BEGIN
class IDisplayer;
class IDisplayFactory
{
virtual IDisplayer* CreateDisplayer(Base* pBase) = 0;
virtual IDisplayer* CreateDisplayer(Child* pBase) = 0;
};
namespace SystemDisplayerFactory
{
static IDisplayFactory* s_pFactory;
SetFactory(IDisplayFactory* pFactory)
{
s_pFactory = pFactory;
}
IDisplayFactory* GetFactory()
{
return s_pFactory;
}
};
// platformcode.h - end
// Base.cpp and Child.cpp implement the "CreateDisplayer" methods as follows
void Base::CreateDisplayer()
{
IDisplayer* pDisplayer = SystemDisplayerFactory::GetFactory()->CreateDisplayer(this);
}
void Child::CreateDisplayer()
{
IDisplayer* pDisplayer = SystemDisplayerFactory::GetFactory()->CreateDisplayer(this);
}
// In your application code, do this:
#include "platformcode.h"
class CDiplayerFactory : public IDisplayerFactory
{
IDisplayer* CreateDisplayer(Base* pBase)
{
return new Displayer(pBase);
}
IDisplayer* CreateDisplayer(Child* pChild)
{
return new Displayer(pChild);
}
}
Then somewhere early in app initialization (main or WinMain), say the following:
CDisplayerFactory* pFactory = new CDisplayerFactory();
SystemDisplayFactory::SetFactory(pFactory);
This will keep your platform code from having to know the messy details of what a "displayer" is, and you can implement mock versions of IDisplayer later to test Base and Child independently of the rendering system.
Also, IDisplayer (methods not shown) becomes an interface declaration exposed by the platform code. Your implementation of "Displayer" is a class (in your app code) that inherits from IDisplayer.