Is there a better way than friend classes here? - c++

Programming in C++ for Windows although this situation could arise anywhere. This is a simplified version of my problem to keep the question manageable so don't get too caught up on the detail :)
I have a class class Window which contains a windows HWND data item. I want to fully encapsulate that HWND so that the user of the class has to go through the class to perform any operations on that window, so it's stored in a private member variable. I don't want to provide any public "getter" for it as that would break the encapsulation allowing the user to bypass my class.
Now I want to create a class class Direct3d11 to encapsulate some of the directx api. In order to create an instance of this class it requires the HWND of a window so I pass it a Window object in it's constructor.
class Direct3D11
{
public:
Direct3D11(const Window& window);
};
Inside the constructor it has access to the window object, however it requires the HWND contained within in order to be able to physically create the windows objects that the Direct3D11 class will manage, but there is no way for it to obtain that information.
I could add a private getter function to get the HWND to the Window class, and then make the Direct3D11 class a friend class of Window so that it call call the function.
However this doesn't seem very elegant not least because class Window has otherwise no need to know anything at all about class Direct3D11.
Am I missing a better way to achieve this? Friend classes don't appeal, and having a public getter function doesn't much appeal either.

You could create the Direct3D11 class inside Window, since Windows owns the HWND.
Something along these lines:
class Window
{
HWND hwnd;
Direct3D11 d;
public:
Window() : d(hwnd) {}
Direct3D11& getDirect3D()
{
return d;
}
}

In your case I suggest to provide a getter for the HWND because you will probably be needing that more often. Providing the getter does not mean that you take the responsibility of your Window class, it is still responsible for the window's life cycle. You just make it more usable and easier to divide your code in use cases.
That said, here is a more generic approach that you could try:
class Window;
class Direct3D {
public:
void apply(Window &window, HWND hWnd);
};
class Window {
public:
void accept(Direct3D &direct3d) {
direct3d.apply(*this, this->m_hWnd);
}
};

You could maybe have a function on Window called Execute. It would take in a std::function with a placeholder for HWND as a parameter. Window would then call the function with HWND as its only parameter.
This would require c++11, but the code would be similar to :
#include <functional>
#include <iostream>
struct Foo {
explicit Foo(int num) : num_(num) {}
template<typename T>
void execute(std::function<T> f) const { f(num_); }
private:
int num_;
};
struct Bar{
void print_nums(int i,int j)
{
std::cout << "i:" << i << ", " << "j:" << j << std::endl;
}
};
int main()
{
Foo o(42);
Bar b;
//the function we want to execute requires an int
//that Foo knows about
typedef void myFunction(int);
// store the result of a call to std::bind
std::function<myFunction> display_1337_first = std::bind(&Bar::print_nums, b,1337, std::placeholders::_1);
std::function<myFunction> display_1337_last = std::bind(&Bar::print_nums, b, std::placeholders::_1, 1337);
o.execute<myFunction>(display_1337_first);
o.execute<myFunction>(display_1337_last);
return 0;
}
//output:
//i:1337, j:42
//i:42, j:1337

If you are willing to use the friend keyword you can make sure window has no knowledge of the class that needs the hwnd. Just make classes (that window and DirectX inherit from) that handle the actions for you. This allows you to solve the problem for DirectX, AND for the next time it comes around.
Side Rant:
Friend is not a four-letter word. Friend, if used reasonably, is actually a great way to add gradation to C++'s access control (public, friend (when in protected), protected, friend (when in private) , private).
#include <iostream>
class HwndOwner;
class HwndWanter
{
protected:
HwndWanter(){}
int getHwndFromOwner(HwndOwner & owner);
};
class HwndOwner
{
protected:
HwndOwner() : hwnd(42){}
private:
friend class HwndWanter;
int getHwnd()
{
return hwnd;
}
int hwnd;
};
class Window : public HwndOwner
{
//This is not the class you are looking for...
};
class Direct3D : private HwndWanter
{
public:
Direct3D(HwndOwner & owner)
: HwndWanter()
{
std::cout << getHwndFromOwner(owner) << std::endl;
}
};
int HwndWanter::getHwndFromOwner(HwndOwner & owner)
{
return owner.getHwnd();
}
int main()
{
Window window;
Direct3D hwndWanter(window);
}
Output:
42

Related

How to pass class with virtual methods around and how to use it as member variable?

I've recently started unit testing my code, using Catch and Fakeit.
I have a wrapper class around the WinAPIs HWND.
class Window
{
public:
Window(HWND hwnd);
virtual void resize(int width, int height);
...
private:
HWND m_hwnd;
};
This and the tests for it work fine. For the tests I'm creating some actual
windows using WinAPI's CreateWindow(...).
However, I've stumbled upon a problem and I'm not sure what's the best solution to it.
In my code I just kept passing Window by value, since it's basically just the HWND anyway.
Some methods take it as const&, but when using it as class members, I usually just copied it.
class Foo
{
public:
Foo(const Window& window)
: m_window(window)
{}
private:
Window m_window;
};
Now lets assume I want to test Foo. I need to somehow stub the Window class, but I can only do that
if I am able to override virtual methods. I think you see the problem here.
class Foo
{
public:
Foo(const std::shared_ptr<Window>& window)
: m_window(window)
{
assert(m_window != nullptr);
}
private:
std::shared_ptr<Window> m_window;
};
I now spent the last two hours, refactoring all my code, so that I only pass std::shared_ptr and almost
never use the Window class by value. Foo now looks like this:
class
This makes sense, cause even if I pass the Window by value, it usually IS shared
anyway (if I resize it, it's resized for all instances).
However, I also felt that it complicated my code ALOT. For the comparison operator== I now always have to derefence
both sides. When I'm trying to find in an stl container, I now have to use
std::find_if(haystack.begin(), haystack.end(),[&needle](const SharedWindowPtr& ptr) { return *ptr == *needle; });
In addition to that, there's overhead from the shared_ptr. I also run the risk of passing nullptrs, where I want to ensure that doesn't happen. I can check that with assertions, but that isn't foolproof. I could also not pass a shared_ptr but a reference to Foo's constructor and give the Window class a std::unique_ptr<Window> clone() method, but I would have to mock that for every test and if there's a way around it I'd prefer that.
Now I'm wondering if there's any better/cleaner method for handling this kind of problem? Thanks for any advice on this.
EDIT: After thinking about this for a while, I had another idea to approach this.
class WindowHandler
{
public:
virtual void resize(int w, int h) = 0;
virtual void getTitle() = 0;
// ...
};
class DefaultWindowHandler
{
public:
DefaultWindowHandler(HWND hwnd);
virtual void resize(int w, int h) override
{
// ...
}
// ...
protected:
HWND m_hwnd;
};
class Window
{
public:
Window(HWND hwnd)
: m_windowHandler(new DefaultWindowHandler(hwnd))
{
// empty
}
void setWindowHandler(WindowHandler* handler)
{
assert(handler != nullptr);
m_windowHandler.reset(handler);
}
void resize(int w, int h)
{
m_windowHandler->resize(w, h);
}
};
What I like about this, is that I can pass the Window class around by value and still get the benefits of the interface-like behaviour if I need to. What do you think about that, what are the shortcomings? I know that the Window should probably accept a WindowHandler instead of the HWND as the constructor argument, but it's just easier to use the way it is.
Following what as been asked in the comment, it seems like std::unique_ptr will suffer from this option too. If taking by value of the base class, using any pointer or reference is not available, you can always use templates:
template<typename WindowType>
struct Foo {
// Want speed? take by value!
Foo(WindowType window)
: m_window(std::move(window))
{}
private:
WindowType m_window;
};
Then, your class will work with all subtypes of window. But then, using template, the functions being virtual or not is irrelevant.
If you want to limit your class Foo to only accept subtypes of windows, you have two choices: sfinae-like or static_assert
sfinae-like
template<typename, typename = void>
struct Foo;
template<typename WindowType>
struct Foo<WindowType, std::enable_if_t<std::is_base_of<Window, WindowType>::value>> {
Foo(WindowType window)
: m_window(std::move(window))
{}
private:
WindowType m_window;
};
static_assert
template<typename WindowType>
struct Foo {
static_assert(std::is_base_of<Window, WindowType>::value, "WindowType must be a subclass of Window");
Foo(WindowType window)
: m_window(std::move(window))
{}
private:
WindowType m_window;
};
The sfinae-like method will have the advantage of being able to "overload" your class for other types that matches with other conditions, but the static_assert is slightly easier to implement.

Why can I call instance functions statically?

I was looking around the Notepad++ source code on GitHub recently, and came across a method call like this:
Window::init(hInst, parent);
I searched for the function it was referencing to, and came across a Window class- but the init function was marked virtual, so clearly it was non-static. Thinking I made a mistake, I checked the entire header to make sure there was no static overload of init, and I made sure there was no Window.cpp file. There isn't.
After poking around the source for 15 more minutes, I gave in and git cloned the repo locally so I could open it in Visual Studio. The first thing I did was to build just to make sure this wasn't an accidental merge on behalf of the project developers- the build succeeded.
The next steps I took:
I opened the the file calling Window::init and clicked Go To Declaration on Window. It takes me to the Window class.
I clicked Go To Declaration on the init function. It points me to the signature of the virtual method.
I copy and paste the Window.h file into an entirely new header and replace all references of Window with Foo. When I type in Foo::init, the compiler complains that 'a nonstatic member reference must be relative to a specific object'.
TL;DR: Somehow, the Notepad++ source code calls a non-static method statically, and this builds. Doesn't work with any other class. Proof here and here.
I have spent 2 hours staring at this, but I still don't see how it's possible. Am I missing something?
No, it's not calling a static function. It's just calling the base class's version of init(). Basically, in tClassName::f, you are asking "I want to call that specific version of the virtual function f() in class tClassName".
Generally, it's pretty common to call the base class's counterpart of a virtual function in the derived class. E.g., the factory method pattern:
#include "tObject.h"
#include "tObject1.h" // public inheritance from tObject
#include "tObject2.h" // public inheritance from tObject
#include "tObject3.h" // public inheritance from tObject
class BaseFactory
{
public:
// factory method
virtual tNode *createObject(int id)
{
if (id == 1) return new tObject1;
else return new tObject2;
}
};
class DerivedFactory: public BaseFactory
{
public:
virtual tNode *createObject(int id)
{
// Overrides the default behavior only for one type
if (id == 1) return new tObject3;
// Call the default factory method for all other types
else return BaseFactory::createObject(id);
}
};
Am I missing something?
Yes - context. Notepad_plus_Window derives from Window, and the call to Window::init() is inside of the Notepad_plus_Window::init() method:
class Notepad_plus_Window : public Window {
public:
...
void init(HINSTANCE, HWND, const TCHAR *cmdLine, CmdLineParams *cmdLineParams);
...
};
void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const TCHAR *cmdLine, CmdLineParams *cmdLineParams)
{
...
Window::init(hInst, parent);
...
}
In this context, Notepad_plus_Window is calling the base class Window version of init().
Maybe this will confuse you less. You're missing context, at no real fault of your own.
You're not seeing the implicit this in the call.
Take the following example:
#include <cstdio>
#include <iostream>
class Foo {
public:
virtual void bar() {
std::cout << "Foo" << std::endl;
}
};
class Bar : public Foo {
public:
virtual void bar() {
std::cout << "Bar" << std::endl;
}
};
int main() {
Bar bar;
bar.bar(); //-> bar
bar.Foo::bar(); //-> foo
Bar *barp = &bar;
barp->bar(); //-> bar
barp->Foo::bar(); //-> foo
return 0;
}
In the above, we can specify the object on which to call a specific method in the class' hierarchy.
It's not a static function. It's calling a function with a specified (class) scope.
By default, init() will match functions within current class scope, if they do exist. that is an implicit this call, equals this->init(),
But with a specified class/namespace prefix, you can explicit call any particular function without dynamic binding. i.e. ::init() will call the init() function within global scope.
the following code may give you a better understanding
#include <iostream>
class A
{
public:
virtual void test()
{
std::cout << "A" << std::endl;
}
};
class B : public A
{
public:
virtual void test()
{
std::cout << "B" << std::endl;
}
};
int main()
{
A* a = new B();
a->A::test();
return 0;
}

C++ an object with its own method?

I'm sorry, this is probably a stupid question. I am obviously misunderstanding something fundamental about object oriented programming. I am used to C and am now trying to use C++.
I have some buttons in a class called Button. Each button does something different. What I want to write is something like this:
Button button1;
Button button2;
...
void button1::onClick () {
...
}
void button2::onClick () {
...
}
But that does not work ("button 1 is not a class, namespace or enumeration" - yes I know!). I know I could just make a separate class for each button:
class button1_class : public Button {
public:
void onclick () {
...
}
} button1;
class button2_class : public Button {
...
}
But to me it 'feels' wrong to make a class when I know for sure it will only have one member.
I'm using Agui, a GUI library for Allegro 5.
EDIT
Thanks for the responses. While they are all helpful and (I think) all valid answers, nobody has actually said yet "no you cannot have an object with its own unique method because..."
So for example, if object1 is of type ObjectClass then object1 is not allowed to have a method (a member function) that is unique to object1, but rather possesses only the methods that are defined as part of ObjectClass. Is that right?
I'm sorry I did not include my actual use case. I was kind of more interested in just getting my head around OOP so that I can do it properly on my own.
EDIT2
Looking at the responses in more detail I suppose it is possible with lambda expressions, it's just not in the way I imagined it. Thanks again
The natural C++ way is to do as vsoftco explained, with virtuals and inheritance.
However, if your Button class has already everything needed, and the only thing that changes between the buttons is the unique (trhow-away) action to be performed, you may want to consider this alternative:
class Button {
function<void()> f;
public:
Button(function<void()> mf) : f(mf) {}
void onClick() { f(); }
};
This variant of your class uses a function object (think of it as a kind of function pointer but much more flexible to use).
You can then use it with lambda-functions as in this example:
int main(int ac, char**av)
{
Button button1([&]() { cout << "Hello 1!\n"; });
Button button2 ([]() { cout << "Hello 2!\n"; });
button1.onClick();
button2.onClick();
}
If the buttons have different functionalities, best thing to do is to create a BaseButton class in which you mark the onclick() as virtual (or make it pure virtual, which will make BaseButton an abstract class), then derive each other button from BaseButton, making sure to override onclick() in each derived class. You then need to use the buttons via a reference or pointer to a BaseButton, this way you achieve what is called "polymorphic behaviour".
For example:
class BaseButton
{
virtual void onclick() {/*implement here or declare pure virtual*/}
};
class RedButton: public BaseButton /* overrides only onclick */
{
void onclick() override { /*specific implementation for Red Buttons */}
};
class ShinyRedButton: public RedButton /* overrides only onclick */
{
void onclick() override { /*specific implementation for Shiny Red Buttons */}
};
then use it like (C++14 smart pointers)
std::unique_ptr<BaseButton> bb = new ShinyRedButton;
bb->onclick(); // will pick up the "right" ShinyRedButton::onclick()` function
You can do this in many ways.
Using a Button class where button objects have a pointer to methods that are invoked onClick. In C you would do this using a callback and you can also do it that way in C++:
class Button {
using funType = void(void);
public:
Button(funType* callback) : function(callback) { }
void onClick() { function(); }
private:
funType* function;
};
However do take note that function pointers are error prone, can't really be inlined by the compiler, and should generally be avoided. This method also works with capture-less lambdas.
Button red([] { std::cout << "Red button\n"; });
Button green(&green_button_function);
Creating different Button objects with different onClick methods on the fly. C++ has a mechanism to do this called templates:
template <class Fun>
class Button {
public:
Button(Fun f) : functor(f) { }
void onClick() { functor(); }
private:
Fun functor;
};
template <class Fun>
Button<Fun> make_button(Fun f) { return Button<Fun>(f); }
I am omitting details such as references on purpose here.
You could then use the Button class with callbacks as well as lambdas in the following way:
auto green = make_button([] { std::cout << "Green button pressed!\n"; });
auto red = make_button(&red_button_function);
You need to use auto with this method because otherwise you would have to specify the type of the functionality by hand, which is not possible e.g. for lambda objects.
Using polymorphism as shown by vsoftco, where you create separate classes for each Button functionality. Or you can make a ButtonAction abstract class to which Button has a reference. Then you implement different functionalities in different classes, but stay with one Button class. This is known as the strategy pattern:
class ButtonAction {
public:
virtual void onClick() = 0;
};
class Button {
public:
Button(std::unique_ptr<ButtonAction> action) :
action_(std::move(action)) {}
void onClick() { action_->onClick(); }
private:
std::unique_ptr<ButtonAction> action_;
};
class RedButtonAction : public ButtonAction {
void onClick() override { red(); }
};
class GreenButtonAction : public ButtonAction {
void onClick() override { green(); }
};
Using this method requires constructing Buttons from ButtonAction unique_ptrs
Button red(std::unique_ptr<ButtonAction>(new RedButtonAction));
Button green(std::unique_ptr<ButtonAction>(new GreenButtonAction));
You're right in that, if each button is fundamentally the same but needs different event handlers bound to it, implementing a new type for each one is not quite right.
Instead your Button type would have a member function that allows users to "attach" an event handler, and a member function to invoke it.
class Button
{
public:
Button()
: onClickHandler()
{}
void setOnClickHandler(std::function<void()> callback)
{
onClickHandler = callback;
}
friend class UI;
private:
void onClick()
{
onClickHandler();
}
std::function<void()> onClickHandler;
};
Then your user does:
void foo()
{
std::cout << "Some buttons do this!\n";
}
Button btn;
btn.setOnClickHandler(foo);
And your program's internals will set up things such that your window manager (above I've assumed that it's some class called UI) invokes btn.onClick() for you, which, since you "attached" foo, will end up invoking foo.
(In modern C++ you'd probably make use of lambda functions to tidy this up, but the above is a simple example to showcase the general design idea.)
In this way, you can attach different handlers to different Button instances, but the Button interface itself is stable.
This is similar to how, for example, you manipulate the DOM in JavaScript.
Using a std::function is the key here. You will have the virtual call overheard and potential memory allocation if your callable (lambda, function, member function) is large. This achieves your requirements of a single type executing different callbacks without defining an class inheritance. Also using uniform initialization makes it very convenient to construct Button class with a lambda without manually creating a constructor.
Live example:
http://coliru.stacked-crooked.com/a/f9007c3f103f3ffe
#include <functional>
#include <vector>
using namespace std;
struct Button
{
function<void()> OnClick;
};
int main()
{
vector<Button> buttons =
{
{[] { printf("Button0::OnClick()\n"); }},
{[] { printf("Button1::OnClick()\n"); }},
{[] { printf("Button2::OnClick()\n"); }},
};
for(auto&& button : buttons)
button.OnClick();
}
Your Agui library supports a signaling system, with the member function addActionListener.
This allows you to derive a class from agui::ActionListener to perform the specific task intended for one or more buttons:
class SimpleActionListener : public agui::ActionListener
{
public:
virtual void actionPerformed(const agui::ActionEvent &evt)
{
std::cout << "Button pushed" << std::endl;
}
};
The object above can be attached to a button's "press" action with:
SimpleActionListener simpleAL;
button1.addActionListener(&simpleAL);

Designing a Window class

I'm planning out a design for my Window class. The goal is to provide an abstraction for creating a platform agnostic window ready for OpenGL rendering. I'm thinking of having a class 'Window' be the public interface, and a 'WindowImpl' class handle the work. Would making Window a friend of WindowImpl and calling WindowImpl functions inside Window cause issues? Technically, WindowImpl wouldn't be instantiated correct? So the destructor wouldn't be called which means the Window destructor wouldn't be called so a destroy function would be needed. Ex.
class MyWindow
{
public:
void create(width, height, title)
{
WindowImpl::create(width, height, title);
open = true;
}
void close()
{
WindowImpl::destroy();
open = false;
}
bool isOpen()
{
return open;
}
private:
bool open;
};
class WindowImpl
{
friend class MyWindow;
private:
static void create(width, height, title) {} // Creates the window
static void destroy()
{
XCloseDisplay(display);
}
static Display* display;
static Window window;
static GLXContext context;
};
I don't know if I'm going in the right way with this, or if I'm making things more complicated then they need to be. Since a different WindowImpl will be compiled depending on the target platform, I want to keep as much of it away from the user as possible, keeping all data like the window title and resolution inside of the Window class and any changes that are necessary can be made without the WindowImpl keeping track of anything more then the implementation specific stuff.
If it really has to be platform-agnostic, then my suggestion is to use something like this:
class WindowImpl
{
public:
virtual void setOwner(Window* pOwner) = 0
virtual void create(width, height, title) = 0;
virtual void close() = 0;
};
class Window
{
public:
void create(width, height, title)
{
mImpl->create(width, height, title);
open = true;
}
void close()
{
open = false;
mImpl->destroy();
}
Window(std::unique_ptr<WindowImpl> pImpl)
: mImpl(pImpl)
{
}
private:
std::unique_ptr<WindowImpl> mImpl;
};
// Then off somewhere else...
class WindowImplX11 : public WindowImpl
{
public:
void setOwner(Window* pOwner) {
mOwner = pOwner;
}
void destroy() {
XCloseDisplay(display);
}
private:
// Pointer back to the owner just in case (e.g. event
// delivery); if weak_ptr worked with unique_ptr, that
// would be better.
Window* mOwner;
Display* display;
GLXContext context;
};
This is a light version of the Bridge pattern, which is commonly used when you have two incompatible object hierarchies which you need to link together. This is a degenerate case (since the "hierarchy" has only one class in it), but it's still a useful technique to think about. Probably the most famous example of this is Java AWT (however AWT calls it "Peer" rather than "Impl").
Exactly how you split the responsibilities between the front end and back end is, of course, something that you need to decide for yourself, and there will probably be some back-and-forth. You may, for example, decide that an OpenGL context is a sufficiently important concept that you need to expose it to clients. The same goes for things like vsync fences which aren't fully supported in the standard way yet. Yes, I'm looking at you, OS X.
The only catch is how you construct a Window and its Impl. The traditional way is to use an abstract factory:
class Toolkit
{
public:
std::unique_ptr<Window> createWindow() = 0;
};
// then elsewhere...
// Should have been in the library, only left out by oversight.
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}
class ToolkitX11 : public Toolkit
{
public:
std::unique_ptr<Window>
createWindow() {
return make_unique<Window>(make_unique<WindowImplX11>());
}
};
There are other ways which are a little more Modern.

C++ "triangle" (and not diamond) inheritance

(I searched and read thru the Diamond- and virtual-inheritance questions here, but could not find an answer. My thinking is that this situation is a little unusual, and I am willing to entertain the ideas that my requirements are somewhat off. On the other hand, I think this should be doable in a "nice" way.)
The situation and the requirements:
I have a C++ class library over which I have no control, and which I cannot change. It defines a Window class. The Window class has a protected member (say: handle), not otherwise accessible, that derived classes are meant to use. Window defines hundreds (well, a very large number...) of methods which I don't care to re-implement by delegating (in a decorator, say).
I want to add functionality to Window, so that derived classes (which I write; say LogWindow) automatically have. An example of such functionality is the ability to snap windows to each other. In order to implement this I need access to Window's protected handle member.
For my real-life purpose this is enough, and the solution is simple: derive SnappableWindow from Window, and derive all my Window-derived classes (LogWindow in this example) from SnappableWindow.
However, what I would really want, and is prettier IMHO, is:
The ability to have this "Snappable" functionality as a standalone piece of code, which I can choose to "plug into" any other Window-derived class, or not.
The ability to extend this notion to other functionalities as well, for example the ability to minimize windows. So I could have a Window-derived class, with or without the "Snappable" ability, and with or without the "Minimizable" ability.
The implementations of "SnappableWindow" and "MinimizableWindow" both need access to Window's handle protected member.
I would like "Snappable" and "Minimizable" to be part of the actual class declaration, so that my actual class (LogWindow) "is a" Window, "is a" SnappableWindow, and "is a" MinimizableWindow.
... and now to the question:
I get how I can do this with declaring SnappableWindow and MinimizableWindow as not deriving from Window but rather getting a handle in their constructor, and then deriving LogWindow from Window and from any combination of SnappableWindow and MinimizableWindow.
EDIT: handle is initialized, in Window, half-way thru LogWindow's constructor, after it has called Window's init(). (and not half way thru Window's constructor, as I've said before).
However, since handle is only initialized half way thru LogWindow's constructor (after it has called Window's init()) , I can't pass is to SnappableWindow and MinimizableWindow as part of LogWindow's constructor initialization list. Rather, I would have to explicitly call some init() method on both, passing it the handle. And this, in each of my Window-derived classes. (LogWindow, SearchWindow, PreferencesWindow, etc.)
I am looking for a way to be able to do something like:
class LogWindow : public Window, public SnappableWindow, public MinimizableWindow
... and not have to implement anything else inside LogWindow. I've fiddled with virtual inheritance, but can't quite come up with the solution.
Virtual inheritance should be able to handle this:
class SnappableWindow: virtual public Window
class MinimizableWindow: virtual public Window
class LogWindow: virtual public Window, public SnappableWindow, public MinimizableWindow
Note that a triangle is just a special case of a diamond!
Window
| \ \---------------\
| \ \
| SnappableWindow MinimizableWindow
| / /
| / /-------------/
LogWindow
Edit: here's a full example:
#include <iostream>
int get_handle() { static int handle = 0; return ++handle; }
struct Window {
int handle;
Window() : handle(get_handle()) { }
};
struct SnappableWindow: virtual public Window {
SnappableWindow() { std::cout << "Snap! " << handle << std::endl; }
};
struct MinimizableWindow: virtual public Window {
MinimizableWindow() { std::cout << "Mm! " << handle << std::endl; }
};
struct LogWindow: virtual public Window, public SnappableWindow, public MinimizableWindow {
LogWindow() { std::cout << "Log! " << handle << std::endl; }
};
int main() {
LogWindow lw;
std::cout << "lw: " << lw.handle << std::endl;
}
Output:
Snap! 1
Mm! 1
Log! 1
lw: 1
You could use traits for that, but unfortunately they can't access protected members. You can do it if you create an intermediate class that exposes the protected member. See if it makes sense:
struct Window {
protected:
int handle;
};
struct BaseWindow : public Window {
int get_handle() { return handle; }
};
template <class TWindow>
struct Snappable {
Snappable() { std::cout << "Snappable " << self()->get_handle() << std::endl; }
private:
TWindow *const self() {
return static_cast<TWindow*>(this);
}
};
template <class TWindow>
struct Minimizable {
Minimizable() { std::cout << "Minimizable " << self()->get_handle() << std::endl; }
private:
TWindow *const self() {
return static_cast<TWindow*>(this);
}
};
struct LogWindow: public BaseWindow, public Snappable<LogWindow>, public Minimizable<LogWindow> {
};
Look here for an interesting architectural style that uses traits.
This is actually a bit confusing... If the handle is initialized as part of the Window constructor, then it will be available after Window constructor completes in the initializer list:
class Window {
protected:
int handle;
Window() { handle = 5; }
};
struct Snappable {
int hdl;
Snappable( int handle ) : handle(handle) {}
};
struct MyWindow : Window, Snappable { // Order matters here!
MyWindow() : Window(), Snappable( handle ) {}
};
int main() {
MyWindow w;
std::cout << w.hdl << std::endl; // 5
}
It is important to note that the order of execution of the base constructors is that of the declaration in the class definition, not the sequence in the initializer list.
That being said, whether this is a good design or not is a different question.