【问题标题】:Overriding template function in specialized daughter class在专门的子类中覆盖模板函数
【发布时间】:2016-02-15 16:42:13
【问题描述】:

我有一个模板化类 MatchBase,其中包含运算符 == 的函数

template<typename Element>
class MatchBase{
    virtual bool operator ==(const MatchBase<Element>& m) const{
    if(_v1 == m.getFirst() && _v2 == m.getSecond()){
        return true;
    }
    return false;
}

我知道有一个模板专用的子类 Match。用于专业化的类Place 没有operator== 来进行比较。因此,我试图覆盖 operator== 以使用 Place 类。

关于我尝试过的事情:

class Match : public betterGraph::MatchBase<graphmatch::Place>{
public :
    Match(const graphmatch::Place& v, const graphmatch::Place& vv) : 
        betterGraph::MatchBase<graphmatch::Place>(v, vv) 
        {};

    virtual bool operator ==(const Match& m) const{
        if(_v1.mass_center == m.getFirst().mass_center && _v2.mass_center == m.getSecond().mass_center){
            return true;
        }
        return false;
    }

};

我也试过

virtual bool operator ==(const betterGraph::MatchBase<graphmatch::Place>& m) const{
    if(_v1.mass_center == m.getFirst().mass_center && _v2.mass_center == m.getSecond().mass_center){
        return true;
    }
    return false;
}

但我总是遇到以下类型的错误:

error: no match for ‘operator==’ (operand types are ‘const AASS::graphmatch::Place’ and ‘const AASS::graphmatch::Place’)
if(_v1 == m.getFirst() && _v2 == m.getSecond()){

因为它试图从基类编译方法。

我有什么办法可以覆盖子类中基类的这个函数吗?我已经阅读了here 的问题,但这是专门的方法,而我的课程是专门的,所以我不知道如何进行前向声明:/。

【问题讨论】:

    标签: c++ templates inheritance template-specialization


    【解决方案1】:

    该函数可能是虚拟的,但在您继承基类时它仍会被初始化。 这是必不可少的,因为您可能会编写如下内容:

    MatchBase<Place> test = Match(p1,p2);
    

    MatchBase&lt;Place&gt;Match 的基类,但它们并不相同。 调用MatchBase&lt;Place&gt;::operator==() 仍然会调用模板基类中定义的函数。

    您现在有多种选择: - 使基类中的函数成为纯虚函数 - 实施Place::operator==() - 将一个比较器作为参数传递给你的基类作为参数

    前两个应该清楚(如果没有请询问)。对于第三个,这可能是一种可能的方法:

    template<typename Element, typename Less = std::less<Element>>
    class MatchBase {
    
    protected:
        Element _v1;
        Element _v2;
    
    public:
        MatchBase(const Element& v, const Element& vv) : _v1(v), _v2(vv)
        {}
    
        virtual bool operator ==(const MatchBase<Element, Less>& m) const {
            Less less;
            bool v1Equal = !less(_v1, m.getFirst()) && !less(m.getFirst(), _v1);
            bool v2Equal = !less(_v2, m.getSecond()) && !less(m.getSecond(), _v2);
            return v1Equal && v2Equal;
        }
    
        const Element& getFirst() const { return _v1; }
        const Element& getSecond() const { return _v2; }
    
    };
    
    struct Place
    {
        int mass_center;
    };
    
    struct PlaceLess
    {
        bool operator()(const Place& p1, const Place& p2) 
        {
            return p1.mass_center < p2.mass_center; 
        };
    };
    
    class Match : public MatchBase <Place, PlaceLess>
    {
    public:
        Match(const Place& v, const Place& vv) :
            MatchBase<Place, PlaceLess>(v, vv)
        {};
    };
    

    另一种方法可能是在这种情况下专门化std::less&lt;T&gt;。所以你不需要将它作为模板参数传递。

    template<typename Element>
    class MatchBase {
    
    protected:
        Element _v1;
        Element _v2;
    
    public:
        MatchBase(const Element& v, const Element& vv) : _v1(v), _v2(vv)
        {}
    
        virtual bool operator ==(const MatchBase<Element>& m) const {
            std::less<Element> less;
            bool v1Equal = !less(_v1, m.getFirst()) && !less(m.getFirst(), _v1);
            bool v2Equal = !less(_v2, m.getSecond()) && !less(m.getSecond(), _v2);
            return v1Equal && v2Equal;
        }
    
        const Element& getFirst() const { return _v1; }
        const Element& getSecond() const { return _v2; }
    
    };
    
    struct Place
    {
        int mass_center;
    };
    
    template<>
    struct std::less<Place>
    {
        bool operator()(const Place& p1, const Place& p2) 
        {
            return p1.mass_center < p2.mass_center; 
        };
    };
    
    class Match : public MatchBase <Place>
    {
    public:
        Match(const Place& v, const Place& vv) :
            MatchBase<Place>(v, vv)
        {};
    };
    

    当然,您可以合并这些方式,以便在需要时覆盖Less 模板参数。

    如果您不打算使用预定义类型(考虑 intstd::string 等...),您还可以确保作为 Element 传递的类必须继承强制执行的类/结构operator== 已实现:

    template <typename T>
    struct IComparable
    {
        virtual bool operator==(const T& other) const = 0;
    };
    
    
    template<typename Element>
    class MatchBase {
    
        static_assert(std::is_base_of<IComparable<Element>, Element>::value, "Element must implement comparable");
    
    protected:
        Element _v1;
        Element _v2;
    
    public:
        MatchBase(const Element& v, const Element& vv) : _v1(v), _v2(vv)
        {}
    
        virtual bool operator ==(const MatchBase<Element>& m) const {
            return _v1 == m._v1 && _v2 == m._v2;
        }
    };
    
    struct Place : public IComparable<Place>
    {
        int mass_center;
    
        bool operator==(const Place& other) const
        {
            return mass_center == other.mass_center;
        };
    };
    
    class Match : public MatchBase <Place>
    {
    public:
        Match(const Place& v, const Place& vv) :
            MatchBase<Place>(v, vv)
        {};
    };
    

    【讨论】:

    • 不模板化std::less 对应于为Place 编写方法== 相同。我想避免用户有更多的东西来编码。我认为最终为 Place 实施== 是最合乎逻辑的:)。感谢您的解释
    • @Malc 我添加了另一个关于如何强制用户实施 operator== 的“解决方案”。
    猜你喜欢
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 2012-05-16
    • 1970-01-01
    • 2016-07-02
    • 1970-01-01
    相关资源
    最近更新 更多