如何在Derived Instantiation之前创建抽象类

时间:2014-03-12 19:20:44

标签: c++ inheritance metaprogramming

如何创建Derived类并在创建派生类时实例化Base类。

喜欢这个

template<class T> 
struct Base 
{
  typedef T type;
  static const int n = 3;
  virtual int f() = 0;
  int f(int x) { return x * 2; }
};

// doesn't compile!
template<class T> 
struct Derived : Base<T> 
{
    type field;         // The compiler doesn't know Base<T>::type yet!
    int f() { return n; } // the compiler doesn't know n yet, and f(int) is maksed!
};

3 个答案:

答案 0 :(得分:3)

您可以使用using声明引入相关名称:

template<class T> 
struct Base 
{
  typedef T type;
  static const int n = 3;
  virtual int f() = 0;
  int f(int x) { return x * 2; }
};

template<class T> 
struct Derived : Base<T> 
{
    using typename Base<T>::type;
    using Base<T>::n;

    type field;
    int f() { return n; }
};

Live example

对于以这种方式继承的类型,您还必须使用typename关键字(如上所述),以便编译器知道名称是指类型。有一个question on SO,其中包含有关此要求的更多信息。

另一种方法是明确限定名称:使用typename Base<T>::type代替typeBase<T>::n代替n。您选择的主要是偏好问题。

答案 1 :(得分:1)

在为某些类型Derived实例化T之前,编译器无法猜测typen应该来自何处。毕竟,在定义Base后,为不同类型提供Derived的专业化是合法的。

您需要改变的是:

template<class T> 
struct Derived : Base<T> 
{
    typename Base<T>::type field; // tell the compiler it's a type,
                                  // and where it comes from
    int f() { return Base<T>::n; }// tell the compiler where n comes from too
};

using声明的工作原理相同,通过限定这些名称,如果您多次使用每个名称,它最终会更清晰。

答案 2 :(得分:0)

您可以通过多种方式执行此操作,如果您希望Derived类自然地使用Base类,您可以尝试使用模板模板。

假设你有相同的基类,那么派生必须看起来像这样:

template< class T, template<typename> class Base > 
struct Derived : Base<T> 
{
    typename Base<T>::type field; 
    int f() 
    {
      return n;
    }
    int f(int x)
    {
      return Base<T>::f(x);
    }
};

但要实例化Derived类,您还需要指定Base类。

喜欢这个

Derived<int, Base> object; 

现在假设您不希望,您只想从 SAME 基类中实例化Derived对象,然后您必须专门化派生模板。

template< class T, template<typename> class Base = Base > 
struct Derived : Base<T> 
{
    Base<T>::type field; 
    int f() 
    {
       return n;
    }
    int f(int x)
    {
        return Base<T>::f(x);
    }
};

这样您现在可以创建Derived<int>Derived<string>

喜欢这个

int main()
{
    Derived<int> bs1;
    bs1.field = 200;
    std::cout << bs1.f() << std::endl;
    std::cout << bs1.f(50)<< std::endl;
    std::cout << bs1.field<< std::endl;

    Derived<std::string> bs2;
    bs2.field = "example";
    std::cout << bs2.f() << std::endl;
    std::cout << bs2.f(50)<< std::endl;
    std::cout << bs2.field<< std::endl;

    return 0;
}

什么时候应该这样做?

当您打算因某种原因切换基类时,可能适用于测试用例。更改基类也可以更改上下文。

您还可以创建一个模板typedef,它允许您将base属性带到您自己的Derived类。这是一个很好的方法。