在专门的子类中覆盖模板功能

时间:2016-02-15 16:42:13

标签: c++ templates inheritance template-specialization

我有一个模板化的类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;
}

我知道有一个专门用于模板的女儿类比赛。用于专业化的类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()){

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

有没有办法让我在子类中覆盖基类的这个函数?我已经阅读了问题here但是这里的方法是专门的,而我的课是专业的,所以我不知道如何做前瞻性声明:/。

1 个答案:

答案 0 :(得分:0)

该函数可能是虚函数,但在继承基类时仍会初始化。 这很重要,因为你可能会这样写:

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

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

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

前两个应该是明确的(如果不是请问)。对于第三种,这可能是一种可能的方法:

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<T>。所以你不需要将它作为模板参数传递。

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)
    {};
};