从超类函数返回子类定义

时间:2014-09-23 11:51:29

标签: c++ templates inheritance

我有两个c ++类,SuperClass&子类。它们中的每一个都有一个set函数,函数最后会返回类对象本身,因为我想在一行中执行它们。代码如下所示:

class SuperClass
{
public:
    SuperClass& SetA(int a)
    {
        m_a = a;
        return *this;
    }
    virtual void Print()
    {
        printf("a=%i", m_a);
    }
protected:
    int m_a;
};
class SubClass : public SuperClass
{
public:
    SubClass& SetB(double b)
    {
        m_b = b;
        return *this;
    }
    virtual void Print()
    {
        printf("a=%i, b=%f", m_a, m_b);
    }
protected:
    double m_b;
};

int main(int argc, char* argv[])
{
    SubClass().SetB(123.4).SetA(123).Print();       // Works fine
    SubClass().SetA(123).SetB(123.4).Print();       // Failed
}

但是,SetA()函数返回SuperClass的定义,所以我不能用SubClass中声明的SetB()函数链接它。

有没有办法让SetA()函数返回SubClass的定义?这样我就可以在一行中执行它们。

提前致谢。 埃利奥特

CRTP方法的问题更新(2014-09-24): 感谢所有评论。我认为CRTP是解决这个问题的好方法。但是,我也想单独使用SuperClass。表示:

int main(int argc, char* argv[])
{
    SubClass().SetB(123.4).SetA(123).Print();       // Works fine
    SubClass().SetA(123).SetB(123.4).Print();       // Failed, but works in CRTP
    SuperClass().SetA(123).Print();                 // Is CRTP able to do this?
}

在这种情况下,CRTP方法是否也有帮助?

提前再次感谢。 埃利奥特

3 个答案:

答案 0 :(得分:2)

  

看来CRTP是解决这个问题的好方法。但是,我可以在这种方法下单独使用SuperClass吗?

DEMO

#include <type_traits>

// make it a template
template <typename T = void>
class SuperClassCRTP
{
    // determine what type SetA (and others) should return
    using CRTP = typename std::conditional<std::is_same<T, void>::value
                                          , SuperClassCRTP
                                          , T>::type;

public:
    // return CRTP& instead:
    CRTP& SetA(int a)
    {
        m_a = a;
        return static_cast<CRTP&>(*this); // cast the *this to desired type
    }

    virtual void Print()
    {
        printf("a=%i", m_a);
    }
protected:
    int m_a;
};

class SubClass : public SuperClassCRTP<SubClass>
//               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
//               specialize the base class with self type
{
public:
    SubClass& SetB(double b)
    {
        m_b = b;
        return *this;
    }
    virtual void Print()
    {
        printf("a=%i, b=%f", m_a, m_b);
    }
protected:
    double m_b;
};

// define an alias
using SuperClass = SuperClassCRTP<>;

int main()
{
    SubClass().SetB(123.4).SetA(123).Print();
    SubClass().SetA(123).SetB(123.4).Print();
    SuperClass().SetA(123).Print();
}

  

我使用VC2005,还有其他选择吗?

您可以自己编写is_sameconditional特征:

DEMO

template <bool b, typename T, typename F>
struct conditional
{
    typedef F type;
};

template <typename T, typename F>
struct conditional<true, T, F>
{
    typedef T type;
};

template <typename T, typename U>
struct is_same
{
    static const bool value = false;
};

template <typename T>
struct is_same<T, T>
{
    static const bool value = true;
};

template <typename T = void>
class SuperClassCRTP
{
    typedef typename conditional<is_same<T, void>::value
                                , SuperClassCRTP
                                , T>::type CRTP;

// ...

typedef SuperClassCRTP<> SuperClass;

int main()
{
    SubClass().SetB(123.4).SetA(123).Print();
    SubClass().SetA(123).SetB(123.4).Print();
    SuperClass().SetA(123).Print();    
}

答案 1 :(得分:2)

您可以像以下示例一样使用curiously recurring template pattern

template<class T>
class SuperClass {
public:
    T& SetA(int a) {
        m_a = a;
        return *dynamic_cast<T*>(this);
    }
    virtual void Print() {
        printf("a=%i", m_a);
    }
protected:
    int m_a;
};
class SubClass : public SuperClass<SubClass>
{
public:
    SubClass& SetB(double b) {
        m_b = b;
        return *this;
    }
    virtual void Print() {
        printf("a=%i, b=%f", m_a, m_b);
    }
protected:
    double m_b;
};

LIVE DEMO

答案 2 :(得分:2)

除了使用编译时多态性的解决方案之外,您还可以使用运行时多态与虚函数来实现类似的结果。为此,您需要在基类中将所有在派生类中使用的函数声明为virtual(可能使用虚拟实现),然后在派生类中重写它们。

#include <cstdio>

class SuperClass {
public:
  SuperClass &SetA(int a) {
    m_a = a;
    return *this;
  }
  virtual void Print() { printf("a=%i", m_a); }
  virtual SuperClass &SetB(double b) { return *this; };

protected:
  int m_a;
};

class SubClass : public SuperClass {
public:
  SubClass &SetB(double b) {
    m_b = b;
    return *this;
  }
  virtual void Print() { printf("a=%i, b=%f", m_a, m_b); }

protected:
  double m_b;
};

int main(int argc, char *argv[]) {
  SubClass().SetB(123.4).SetA(123).Print();
  printf("\n");
  SubClass().SetA(123).SetB(123.4).Print();
}