1

我想写一些字符串包装器,如果它对其类型有效,它们将接受一个字符串:

  • Length有效字符串:mm、m、ft、in
  • Angle 有效字符串:度、弧度

我想像这样的用途:

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";
   }  
};

但现在我失去了基类中的隐式构造函数,我必须重写它们!

有没有其他方法可以实现它以便拥有相同的接口 [default constructor和]implicit constructor并且is_value()只为不同的部分(静态)编写最少的代码is_valid_string()

我知道我可以使用预处理器,但我希望代码对调试器友好。

4

4 回答 4

1

构造函数不是继承的,你不能用using.

在 C++11 中,您可以使用可变参数模板和完美转发:

template<typename... Args> Derived(Args &&...args):
    Base(std::forward<Args>(args)...) {}
于 2012-09-10T16:40:19.360 回答
1

正如其他人所指出的,由于构造函数不是继承的,因此您必须重新定义它们。但是,您可以在 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;
   }
}
于 2012-09-10T17:27:03.993 回答
0

由于构造函数在 C++ 中永远不会被继承(如果没有定义构造函数,则默认除外),您要么自己再次实现它们,要么模板化(使用或不使用 C++11 可变参数模板)以使编译器与构造函数匹配。但是请注意,这样做会使文档和编译器错误更难解释,因为无意义的模板构造函数添加了(有时)令人困惑的抽象层。

预处理器运算符也可以解决这个问题,但我只会在构造函数非常简单且易于在所有继承者之间复制的情况下这样做。

所以一般来说,如果你可以干净地生成一个继承的默认构造函数和一个隐式构造函数,答案是否定的。但是上面概述的两种方法会以一种有点混乱但自动的方式来完成。

于 2012-09-10T16:54:55.510 回答
0

我使用了一个策略,它节省了一天。现在我不必重写构造函数,只需要实现is_valid_string(). 它现在也兼容 C++98。

template <class Policy>
struct ConstrainedText {
  QString m;

  ConstrainedText() {}

  ConstrainedText( QString s ) {   if( Policy::is_valid_string(s) )   {  m = s;  }    }

  QString operator() ()        {   return m;      }

  bool is_valid()              {   return Policy::is_valid_string(m);    }

};


struct Angle_policy {
   static bool is_valid_string( QString s ) { 
      return s == "deg" || s="rad";
   }  
};

struct Length_policy {
   static bool is_valid_string( QString s ) { 
      return s == "mm" || s="m" || s=="ft" || s=="in";
   }  
};

typedef ConstrainedText<Length_policy> Length;
typedef ConstrainedText<Angle_policy>  Angle;

谢谢大家的帮助

于 2012-09-11T08:37:44.003 回答