我想写一些字符串包装器,如果它对它们的类型有效,它将接受一个字符串:
长度
有效字符串:mm、m、ft、inAngle
有效字符串:deg, rad
我想象这样的用途:
Length len = read_from_keyboard(); // or some means of initialization
if( len.is_valid() ) { ... }
所以我写了这些实现。
struct Length
{
QString m;
Length() {}
Length( QString s ) { if( is_valid_string(s) ) { m = s; } }
QString operator() () { return m; }
bool is_valid() { return is_valid_string(m); }
static bool is_valid_string( QString s ) {
return s == "mm" || s=="m" || s=="ft" || s=="in";
}
};
和
struct Angle{
QString m;
Angle() {}
Angle( QString s ) { if( is_valid_string(s) ) { m = s; } }
QString operator() () { return m; }
bool is_valid() { return is_valid_string(m); }
static bool is_valid_string( QString s ) {
return s == "deg" || s=="rad";
}
};
这在我看来是某种形式的静态多态性,is_valid_string()
是它们在实现上的唯一区别。
因为我有很多这样的类,所以我想到使用静态继承(而不是通过虚拟继承)来掌握通用功能。
所以,我想到了使用奇怪的重复模板模式:
template <class T>
struct ConstrainedText {
QString m;
ConstrainedText() {}
ConstrainedText( QString s ) { if( T::is_valid_string(s) ) { m = s; } }
QString operator() () { return m; }
bool is_valid() { return T::is_valid_string(m); }
};
struct Angle : public ConstrainedText<Angle> {
static bool is_valid_string( QString s ) {
return s == "deg" || s="rad";
}
};
struct Length : public ConstrainedText<Angle> {
static bool is_valid_string( QString s ) {
return s == "mm" || s="m" || s=="ft" || s=="in";
}
};
但现在我丢失了基类中的隐式构造函数,我必须重写它们!
为了拥有相同的接口(interface) [default constructor
, implicit constructor
and is_value()
有没有其他方法可以实现它] 并且只为不同的部分编写最少的代码(静态 is_valid_string()
)?
我知道我可以使用预处理器,但我希望代码对调试器友好。
最佳答案
正如其他人所指出的,由于构造函数不是继承的,因此您将不得不重新定义它们。但是你可以做这样的事情,code at ideone.com :
#include <string>
#include <stdexcept>
#include <iostream>
template <class T>
class ConstrainedText {
std::string m;
protected:
ConstrainedText() {}
~ConstrainedText() {}
public:
bool is_valid() {
return T::is_valid_string(m);
}
static T Create(std::string const & s)
{
if (T::is_valid_string(s)) {
T t;
static_cast<ConstrainedText<T>&>(t).m = s;
return t;
}
throw std::runtime_error("invalid input!");
}
};
struct Angle : public ConstrainedText<Angle> {
static bool is_valid_string( std::string s ) {
return s == "deg" || s=="rad";
}
};
struct Length : public ConstrainedText<Length> {
static bool is_valid_string( std::string s ) {
return s == "mm" || s == "m" || s == "ft" || s == "in";
}
};
int main()
{
auto a = Angle::Create("deg");
auto l = Length::Create("mm");
try {
Angle::Create("bimbo");
} catch (std::runtime_error & pEx) {
std::cout << "exception as expected" << std::endl;
}
try {
Length::Create("bimbo");
} catch (std::runtime_error & pEx) {
std::cout << "exception as expected" << std::endl;
}
}
关于c++ - 重构为模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12355841/