通过模板进行多重继承

时间:2015-05-08 11:24:24

标签: c++ templates inheritance multiple-inheritance diamond-problem

用teplates inheritence(线性)替换虚拟多重继承(diamon)是个好主意吗?例如,我有这个类图:

public class Pause implements MouseListener{

    private Rectangle2D resumeRect;
    private Rectangle2D restartRect;

    public Pause(GameFrame GameFrame) {
        GameFrame.addMouseListener(this);
    }


    public void draw(Graphics2D g) {        
        g.setFont(new Font("Arial", Font.BOLD, 14));
        int intValue = Integer.parseInt( "ff5030",16);      
        g.setColor(new Color(intValue));

        g.drawString("Resume", 200, 156);
        resumeRect= g.getFontMetrics().getStringBounds("Resume", g);

        g.drawString("Restart", 200, 172);
        restartRect = g.getFontMetrics().getStringBounds("Restart", g);

        g.drawString("Quit", 200, 188);
    }


    public void mouseClicked(MouseEvent e) {
        if (resumeRect.contains(e.getPoint())) {
            System.out.println("clicked");
        }

        System.out.println(resumeRect);
        System.out.println(restartRect);
        System.out.println(e.getPoint());
    }


    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}

}

我知道我可以使用虚拟继承来实现它。但是我可以使用模板来使这个图呈线性吗?

       IBase
    /          \
   /            \
IExtendedBase  BaseImpl
  \            /
   ExtendedImpl

现在使用typedef我可以专门使用ExtendedBase

class IBase
    {
    public:
        virtual std::string name() = 0;
    };

    template<typename T>
    class BaseImpl : public T
    {
    public:
        virtual std::string name() override
        {
            return "BaseCommonImpl";
        }
    };

    template<typename T>
    class IExtendedBase : public T
    {
    public:
        virtual std::string extended_name() = 0;
    };

    template<typename T>
    class ExtendedBaseImpl : public T
    {
    public:
        virtual std::string extended_name() override
        {
            return "ExtendedBaseImpl";
        }
    };

哪种方法更好?虚拟继承或模板继承?

2 个答案:

答案 0 :(得分:2)

虽然使用这两种不同的方法(多重继承与模板)可以获得类似的结果,但是存在重要的语义差异。

不幸的是,您没有提供足够的信息来推荐客观选择。所以这里有一些注意事项:

多重继承方法

多重继承旨在强制执行有效的 separation of concerns

如果在您的情况下ExtendedImpl IExtendBase并且同时 是-a,则应首选此方法 BaseImpl,但两种继承关系都是独立的。

在某些情况下(例如,铸造)会带来轻微性能开销的不便。

但它的优点是允许在ExtendedImpl使用任何基础的地方使用ExtendedImpl。此外,它允许动态的,基于运行时的多态性(如果它的任何基础具有虚拟成员函数)。

enter image description here

模板方法

模板适用于通用编程。如果您的var_export($variable, true)非常通用,并且“基础”是您的通用概念的更多参数,而不是进一步扩展的概念,则应优先采用此方法。

模板在这里会有稍微好一点的性能(单继承)。但是,您没有实现初始架构的原始概念。而且你没有动态多态的灵活性。

enter image description here

如果类型之间的关系不具有通用性,那么您可能会在此处引发不期望的依赖关系。例如,IExtendedBase将从BaseImpl继承。在许多情况下这可能没问题。但在其他情况下可能完全不自然,导致在维护阶段出现持久的设计问题。

<强>结论

现在由您来决定哪种优势和不便最适合您的具体情况。如果需要,您可以编辑您的问题,以更准确地指示背景和您的意图,我将调整答案 因此。

答案 1 :(得分:-1)

这个问题是对意见的要求,因此可能会被主持人关闭。

在此之前,我的建议是支持避免多重继承的方法:

#include <iostream>
#include <string>

class IBase
{
public:
    virtual std::string name() = 0;
};


class IExtendedBase : public IBase
{
public:
    virtual std::string extended_name() = 0;
};


template<typename T>
class BaseImpl : public T
{
public:
    virtual std::string name() override
    {
        return "BaseCommonImpl";
    }
};

template<typename T>
class ExtendedBaseImpl : public T
{
    using inherited = T;
public:
    virtual std::string extended_name() override
    {
        return "ExtendedBaseImpl";
    }

    // optionally override name if you wish
    std::string name() override {
        return inherited::name() + "(extended)";
    }
};

typedef BaseImpl<IBase> Base;
typedef ExtendedBaseImpl<BaseImpl<IExtendedBase>> ExtendedBase;


using namespace std;

int main()
{

    Base a;
    a.name();
    cout << a.name() << endl;

    ExtendedBase b;
    cout << b.extended_name() << endl;
    cout << b.name() << endl;

}
相关问题