2009-10-21 72 views
0

我有一个装饰者样式的基础,需要一个构造参数。装饰器的构造方式是它可以将任意数量的附加组件作为模板参数(本例中最多3个)。装饰者需要一个构造参数的基础

不幸的是,当指定多个加载项时,我无法弄清楚如何将基础的构造函数参数传递给它。在下面的示例中,CMyClass<AddOn_A> A(100);完美工作,但CMyClass< AddOn_A, AddOn_B > AB(100);在CMyClass构造函数中生成错误。

template< class Base > 
class AddOn_A : public Base 
{ 
public: 
    AddOn_A(int x) : Base(x) 
    { 
    }; 

    int AddOne() 
    { 
     return static_cast< Base* >(this)->DoSomething() + 1; 
    }; 
}; 

template< class Base > 
class AddOn_B : public Base 
{ 
public: 
    AddOn_B(int x) : Base(x) 
    { 
    }; 

    int AddTwo() 
    { 
     return static_cast< Base* >(this)->DoSomething() + 2; 
    }; 
}; 

class CBase 
{ 
public: 
    explicit CBase(int x) : x_(x) 
    { 
    }; 

    int DoSomething() 
    { 
     return x_; 
    }; 

private: 
    int x_; 
}; 

// define an empty AddOn 
template<class> class empty {}; 

// forward declaration and Add-On defaults 
template< template<class> class AddOn1 = empty, 
      template<class> class AddOn2 = empty, 
      template<class> class AddOn3 = empty > 
class CMyClass; 

// specialized template for the default case 
template<> class CMyClass< empty, empty, empty > {}; 

// actual definition 
template< template<class> class AddOn1, 
      template<class> class AddOn2, 
      template<class> class AddOn3 > 
class CMyClass : public AddOn1<CBase>, 
       public CMyClass< AddOn2, AddOn3 > 
{ 
public: 
    // what needs to go here??? 
    CMyClass(int x) : AddOn1<CBase>(x) 
    {}; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    // works 
    CMyClass<AddOn_A> A(100); 
    _ASSERT(A.AddOne() == 101); 

    // works 
    CMyClass<AddOn_B> B(100); 
    _ASSERT(B.AddTwo() == 102); 

    // generates an error at the CMyClass ctor: 
    // error C2512: 'CMyClass<AddOn1>' : no appropriate default constructor available 
    CMyClass< AddOn_A, AddOn_B > AB(100); 
    _ASSERT(AB.AddOne() == 101); 
    _ASSERT(AB.AddTwo() == 102); 

    return 0; 
} 

如果有人能指出我可能做错了什么,请告诉我。

感谢, PaulH

回答

2

你的错误通常源于出来的事实,CMyClass没有默认构造函数(因为你定义一个CMyClass(int)代替),所以需要与CMyClass(int)构造函数,你必须明确实例你的父母。因此,举例来说,在你的CMyClass定义你需要调用在初始化列表中添加到CMyClass(int)现在,我们有CMyClass发送x上下行

CMyClass(int x) : AddOn1<CBase>(x), CMyClass<AddOn2, AddOn3>(x) //send x down 

,有必要对您的基本情况专业化(CMyClass<empty, empty, empty> )到现在为止已经接受x,但确实与它无关

template<> 
class CMyClass<empty, empty, empty> { 
public: 
    CMyClass(int) {} //do nothing 
}; 

现在,编译器能够找到合适的构造函数和像您期望

创建类构造函数

只是为了解释为什么像CMyClass<AddOn_A> A(100)运行线路,这是因为A(在这个例子)只有一个父,CMyClass<empty, empty, empty>,和您的专业

template<> class CMyClass< empty, empty, empty > {}; 

有一个默认的构造函数,因为它是空的(或者更正式地说,因为它没有定义其他构造函数)。一旦你调用CMyClass<AddOn_A, AddOn_B> AB(100),因为它有两个父母,CMyClass<AddOn_B, empty, empty>CMyClass<empty, empty, empty>,但是前者没有默认构造函数,所以编译器不知道如何构造它。这就是为什么我们必须将这一行添加到初始化列表中,所以我们告诉编译器使用它的CMyClass(int x)构造函数创建CMyClass<AddOn_B, empty, empty>(注意这意味着编译器将如何使CMyClass<empty, empty, empty>参数为x,所以我们需要添加一个构造函数到将接受参数的专业化)。

+0

完美的作品。感谢您的解释! – PaulH 2009-10-21 22:08:02

0
  • 它不是立即清楚你想达到的目标。我希望你不会混淆继承和模板。

  • empty,AddOn_AAddOn_B是类模板。他们不是一个阶级的例子。你需要有实际的课程。

+0

我不认为我很困惑。每个附加组件都为CBase提供附加功能。 我正在使用递归模板模式,以方便用户使用,而不会导致运行时间损失。 此外,它适用于一个插件,它只需要调整多个插件。 – PaulH 2009-10-21 20:04:02

相关问题