Reputation: 77
I am trying to fit Mixin pattern to my problem and I have one problem with polymorphism, which I don't know how to solve effectively. I want to ask you for advice (maybe there is some cool c++ feature I am not aware of) before trying to redesign my program.
I want to present it in very straightforward and easy way, so the use case here might not make sense.
I have simply a Window
class
struct WindowCreateInfo {
std::string title;
int x, y;
int width, height;
};
class Window {
public:
Window(const WindowCreateInfo &createInfo) :
title(createInfo.title),
x(createInfo.x),
y(createInfo.y),
width(createInfo.width),
height(createInfo.height) {}
const std::string &getTitle() const { return title; }
int getX() const { return x; }
int getY() const { return y; }
int getWidth() const { return width; }
int getHeight() const { return height; }
public:
protected:
std::string title;
int x, y;
int width, height;
};
Then I define two mixins Resizable
and Movable
as follows
template<class Base>
class Resizable : public Base {
public:
Resizable(const WindowCreateInfo &createInfo) : Base(createInfo) {}
void resize(int width, int height) {
Base::width = width;
Base::height = height;
}
};
template<class Base>
class Movable : public Base {
public:
Movable(const WindowCreateInfo &createInfo) : Base(createInfo) {}
void move(int x, int y) {
Base::x = x;
Base::y = y;
}
};
Next, I have some business layer where I work with instances of Window
class WindowManager {
public:
static void resize(Resizable<Window> &window, int width, int height) {
window.resize(width, height);
// any other logic like logging, ...
}
static void move(Movable<Window> &window, int x, int y) {
window.move(x, y);
// any other logic like logging, ...
}
};
The obvious problem here is that following does not compile
using MyWindow = Movable<Resizable<Window>>;
int main() {
MyWindow window({"Title", 0, 0, 640, 480});
WindowManager::resize(window, 800, 600);
// Non-cost lvalue reference to type Movable<Window> cannot bind
// to a value of unrelated type Movable<Resizable<Window>>
WindowManager::move(window, 100, 100);
};
I understand that there is difference between Movable<Window>
and Movable<Resizable<Window>>
because the latter Movable
could use Resizable
. In my design, the mixins are independent and the order in which they are mixed in does not matter. I guess this use of mixins is very common.
Is there any way how to make this code compile while keeping the design as much as possible?
Upvotes: 3
Views: 303
Reputation:
Is there any way how to make this code compile while keeping the design as much as possible?
You can simply make the window manager accept arbitrary versions of Resizable<>
and Movable<>
by templating the methods:
class WindowManager {
public:
template<typename Base>
static void resize(Resizable<Base> &window, int width, int height) {
window.resize(width, height);
// any other logic like logging, ...
}
template<typename Base>
static void move(Movable<Base> &window, int x, int y) {
window.move(x, y);
// any other logic like logging, ...
}
};
Upvotes: 5