簡體   English   中英

類模板中的運算符重載和友誼

[英]Operator overload in class templates and friendship

假設我有一個小班模板如下

template<typename T> class SillyClass {
public:

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

private:

  T data;

};

現在我添加以下 定義 聲明:

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),我有哪些替代方案?

謝謝。

您不僅可以在類中聲明運算符,還可以在類中定義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);

並且每當您在SillyClass<int>和一些int上調用您的operator+時,都會比上面的模板定義更好的匹配。 因此鏈接器將無法找到所需int實例化的定義,因此會出現鏈接器錯誤。 另一方面,我在答案開頭提出的解決方案保證每種類型都有相應的定義,因此它可以毫無問題地工作。

我的班級在這里交朋友是為了什么? 為什么要額外的模板聲明?

在您的類中聲明的以下表達式是友元聲明

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

上面的表達式將您的類聲明為具有一系列重載operator+的朋友,這些operator+將類型TT作為其左側參數,並將對象SillyClass<TT>作為其右側。 請注意,這是一個聲明而不是定義。 也就是說,為了使其工作,必須定義模板重載operator+

對於導致相同結果的不同聲明(例如,能夠執行 3+a),我有哪些替代方案?

對於二元運算符,為了使它們對稱,必須在類定義之外將其聲明為自由函數,並且為了能夠訪問其類參數的私有成員,您將它們聲明為相應類的友元函數。

基於這些行,我將采用以下實現:

template<typename T> class SillyClass {
  T data;
public:
  SillyClass(const T val) : data(val) {}
  SillyClass(const SillyClass& other) : data(other.data) {}

  template<typename T1, typename T2>
  friend SillyClass<typename std::common_type<T1, T2>::type> 
  operator+(SillyClass<T1> const &lsh, SillyClass<T2>& rhs);

  template<typename T1, typename T2>
  friend SillyClass<typename std::common_type<T1, T2>::type> 
  operator+(SillyClass<T1> const &lsh, T2 const &rhs);

  template<typename T1, typename T2>
  friend SillyClass<typename std::common_type<T1, T2>::type> 
  operator+(T1 const &rhs, SillyClass<T2> const &rsh);
};

template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type> 
operator+(SillyClass<T1> const &lhs, SillyClass<T2>& rhs) {
  return SillyClass<typename std::common_type<T1, T2>::type>(lhs.data + rhs.data);
}

template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type> 
operator+(SillyClass<T1> const &lhs, T2 const &rhs) {
  return SillyClass<typename std::common_type<T1, T2>::type>(lhs.data + rhs);
}

template<typename T1, typename T2>
SillyClass<typename std::common_type<T1, T2>::type> 
operator+(T1 const &lhs, SillyClass<T2> const &rhs) {
  return SillyClass<typename std::common_type<T1, T2>::type>(rhs.data + lhs);
}

現場演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM