【问题标题】:Using friend to reduce verbosity使用朋友来减少冗长
【发布时间】:2016-06-10 05:23:06
【问题描述】:

使用friend 在类定义中定义全局函数是否被认为是一种好习惯,即使不需要访问私有成员也是如此。例如

template<typename T>
class A {
public:
    A(T v);
    T value() const;

    friend A operator+(T n, const A& a) {
        return A(a.value() + n);
    }
};

而不是

template<typename T>
class A {
public:
    A(T v);
    T value() const;
};

template<typename T>
A<T> operator+(T n, const A<T>& a) {
    return A<T>(a.value() + n);
}

即使operator+ 只使用公开的value()。 这个是常做的吗,我们不推荐吗?

【问题讨论】:

  • 你为什么要打破你的封装?如果您不需要封装,只需将所有成员公开即可。如果要封装,不要左右交友。
  • 不推荐。
  • 友元函数的一个优点是它不是模板,并且在某些情况下会更改重载顺序解析。
  • @SergeyA 类中内联的friend 函数的定义在哪里打破了封装规则
  • @πάνταῥεῖ,你为什么要给不需要访问私有成员的函数加好友?

标签: c++ templates operator-overloading friend


【解决方案1】:

friend 有一个主要优势。当我们定义:

friend A operator+(T, const A&);

不是一个函数模板。这只是一个功能——一个只有 ADL 才能找到的特殊功能。但由于它不是函数模板,因此仍然可以进行转换。另一方面:

template <class T>
A<T> operator+(T, const A<T>&)

是一个普通的旧函数模板,具有关于模板类型推导的所有普通规则。

为什么这很重要?考虑:

A<double> a(4.2);
5 + a;

在第一种情况下,这完全没问题。我们找到operator+(double, const A&lt;double&gt;&amp;),将5 转换为5.0,这是允许的转换,我们返回A&lt;double&gt;(9.2)

在第二种情况下,模板推导失败,因为 T 推导两个参数的不同类型。因此,代码格式不正确。

【讨论】:

  • 假设模板更改为template &lt;class X, class T&gt;,您可以在不诉诸friendstd::is_convertible&lt;X, T&gt; 的情况下模仿这种行为,对吧?
  • @KurtStutsman 是的,但是模板函数 + SFINAE 比一个简单的函数要复杂得多......
  • 我猜当函数不是成员但在语义上是类的一部分时,使用friend 是可以的。因为成员函数也并不总是需要对类具有私有访问权限。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-30
  • 1970-01-01
相关资源
最近更新 更多