类模板和友谊中的运算符重载

时间:2015-11-26 21:22:21

标签: c++ templates

假设我有一个小类模板,如下所示

template<typename T> class SillyClass {
public:

  SillyClass(const T val);
  SillyClass(const SillyClass& other);

private:

  T data;

};

现在我添加以下 definitions 声明:

template<typename T> class SillyClass {
public:

  SillyClass(const T val);
  SillyClass(const SillyClass& other);

  SillyClass<T> operator+ (const SillyClass& other);
  SillyClass<T> operator+ (const T& val);

private:

  T data;

};

现在(在我写完适当的定义之后)我可以做像

这样的事情
SillyClass<int> a(1);
SillyClass<int> b(a);
SillyClass<int> c = a + b;
SillyClass<int> d = a + 3;

到目前为止,这么好。但是,能够写出像

这样的东西
SillyClass<int> e = 3 + a;

我发现必须将以下声明添加到我的班级

  template<typename T2> friend SillyClass<T2> operator+ 
    (const T2& val, const SillyClass<T2>& other);

所以它现在读取

template<typename T> class SillyClass {
public:

  SillyClass(const T val);
  SillyClass(const SillyClass& other);

  SillyClass<T> operator+ (const SillyClass& other);
  SillyClass<T> operator+ (const T& val);

  template<typename TT> SillyClass<TT> friend operator+ 
    (const TT& val, const SillyClass<TT>& other);

private:

  T data;

};

我没有在书中找到这个,我想帮助了解最后一个声明中发生了什么。例如,我的班级在这里结识了什么?为什么要附加模板声明?在导致相同结果的不同声明(能够执行3 + a,比方说)方面,我有哪些替代方案?

感谢。

2 个答案:

答案 0 :(得分:1)

您可以定义您班级中的friend运算符,而不是仅在课堂上声明您的运算符:

SillyClass<T> friend operator+(const T& val, const SillyClass<T>& other)
{
    // define it here
}

这样,对于每个类的实例,都会生成相应的friend。整个过程基于名为朋友名称注入的东西。

现在回到你的问题。如果您只是使用课堂内声明

friend operator+(const T& val, const SillyClass<T>& other);

然后在课堂外定义

template<typename T>
friend operator+(const T& val, const SillyClass<T>& other)

您将收到链接器错误。为什么?因为在实例化类时假设T=int。然后你班上的宣言将读为

friend operator+(const int& val, const SillyClass<int>& other);

,只要您在operator+SillyClass<int>上调用int,就会比上面的模板定义更好地匹配。因此链接器将无法找到所需int实例化的定义,因此会出现链接器错误。另一方面,我在答案开始时提出的解决方案保证 每个类型的相应定义,因此它可以毫无头痛地工作。

答案 1 :(得分:1)

  

我的班级在这里结识了什么?为什么要附加模板声明?

在您的类中声明的以下表达式是friend declaration

template<typename TT> SillyClass<TT> friend operator+ 
    (const TT& val, const SillyClass<TT>& other);

上面的表达式将您的类声明为一个重载operator+系列的朋友,将其左侧参数作为类型TT并将其右侧作为对象{ {1}}。请注意,这是一个声明而不是定义。也就是说,为了使模板重载SillyClass<TT>,必须定义它。

  

对于不同的声明,我有哪些替代方案   导致相同的结果(能够执行3 + a,比如说)?

对于二元运算符,为了使它们对称,必须在类定义之外声明为自由函数,并且为了能够访问其类参数的私有成员,可以将它们声明为相应类的友元函数。

基于这些内容,我将继续以下实施:

operator+

Live Demo