当前位置:  开发笔记 > 编程语言 > 正文

方法链接+继承不能很好地结合在一起?

如何解决《方法链接+继承不能很好地结合在一起?》经验,为你挑选了2个好方法。

考虑:

// member data omitted for brevity

// assume that "setAngle" needs to be implemented separately
// in Label and Image, and that Button does need to inherit
// Label, rather than, say, contain one (etc)

struct Widget {
    Widget& move(Point newPos) { pos = newPos; return *this; }
};

struct Label : Widget {
    Label& setText(string const& newText) { text = newText; return *this; }
    Label& setAngle(double newAngle) { angle = newAngle; return *this; }
};

struct Button : Label {
    Button& setAngle(double newAngle) {
        backgroundImage.setAngle(newAngle);
        Label::setAngle(newAngle);
        return *this;
    }
};

int main() {
    Button btn;

    // oops: Widget::setText doesn't exist
    btn.move(Point(0,0)).setText("Hey");

    // oops: calling Label::setAngle rather than Button::setAngle
    btn.setText("Boo").setAngle(.5); 
}

有什么技巧可以解决这些问题吗?

示例:使用模板魔术使Button :: move返回Button等.

编辑很明显,第二个问题是通过使setAngle虚拟解决的.

但第一个问题仍未以合理的方式解决!

编辑:嗯,我想在C++中做不到是不可能的.无论如何,谢谢你的努力.



1> Konrad Rudol..:

您可以扩展CRTP来处理此问题.monjardin的解决方案朝着正确的方向发展.您现在需要的只是一个默认Label实现,将其用作叶类.

#include 

template 
struct Default {
    typedef Q type;
};

template 
struct Default {
    typedef T type;
};

template 
void show(char const* action) {
    std::cout << typeid(T).name() << ": " << action << std::endl;
}

template 
struct Widget {
    typedef typename Default >::type type;
    type& move() {
        show("move");
        return static_cast(*this);
    }
};

template 
struct Label : Widget > {
    typedef typename Default > >::type type;
    type& set_text() {
        show("set_text");
        return static_cast(*this);
    }
};

template 
struct Button : Label > {
    typedef typename Default > >::type type;
    type& push() {
        show("push");
        return static_cast(*this);
    }
};

int main() {
    Label<> lbl;
    Button<> btt;

    lbl.move().set_text();
    btt.move().set_text().push();
}

也就是说,考虑这样的努力是否值得小额添加语法奖励.考虑其他解决方案


+1,很好的技巧 - 你将最派生的类型作为类型参数T传递,使用"void"作为标志来说"实际上*这*是最派生的类型".但我同意要付出很多努力......

2> jalf..:

对于第二个问题,使setAngle虚拟化可以解决问题.

对于第一个,没有简单的解决方案.Widget :: move返回一个Widget,它没有setText方法.你可以创建一个纯虚拟的setText方法,但这是一个非常难看的解决方案.你可以在按钮类上重载move(),但这很难维护.最后,您可以使用模板执行某些操作.也许是这样的:

// Define a move helper function
template 
T& move(T& obj, Point& p){ return obj.move(p); };

// And the problematic line in your code would then look like this:
move(btn, Point(0,0)).setText("Hey");

我会让你决定哪种解决方案最干净.但是,为什么你需要能够链接这些方法有什么特别的原因吗?

推荐阅读
手机用户2402851335
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有