我有两个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方法是否也有帮助?
提前再次感谢。 埃利奥特
答案 0 :(得分:2)
看来CRTP是解决这个问题的好方法。但是,我可以在这种方法下单独使用SuperClass吗?
#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_same
和conditional
特征:
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;
};
答案 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();
}