c ++ friend关键字是否意味着对私有的访问更多?

时间:2019-02-26 16:44:18

标签: c++ friend-function

我写了简单的类并定义了一个副本构造函数。 然后添加朋友等于比较运算符,并将intInt

template <class T>
class Int {
public:
    T value;
    Int(const T& value_) : value(value_) {
        ;
    }

    friend bool operator==(const Int<T>& f, const Int<T>& s) {
        return f.value == s.value;
    }
};

int main() {
    int a;
    Int<int> x(a);
    x == a;
}

编译成功。

如果我将friend bool operator==(const Int<T>& f, const Int<T>& s);变成非朋友模板。我收到编译器错误:

error: no match for 'operator==' (operand types are 'int' and 'Int<int>'
template <class T>
class Int {
public:
    T value;
    Int(const T& value_) : value(value_) {
        ;
    }
};

template <class T>
bool operator==(const Int<T>& f, const Int<T>& s) {
    return f.value == s.value;
}

int main() {
    int a;
    Int<int> x(a);
    x == a;
}

这是否意味着朋友功能允许特定的转换?

5 == x也可以。

1 个答案:

答案 0 :(得分:1)

  

c ++朋友关键字是否意味着比私人访问更多?

取决于上下文,它可能具有更多含义,是的。例如,一个friend内联定义的函数,没有其他声明,即使它是封闭名称空间的成员,也只能通过依赖于参数的查找来找到:

namespace foo {
    struct bar {
        friend void baz(bar const&) {}
    };
}

int main() {
    foo::bar bar;
    // foo::baz(bar); // ill-formed, no member baz in foo
    baz(bar); // Okay, it *can* be found by ADL
};

这与您的问题没有直接关系,但是这就是查找朋友operator==的方式。那个朋友也不是一个模板。实例化Int<int>时,这会将“ operator==”的免费功能(同样不是模板)“注入”到名称空间Int的成员中。当出于执行x == a的目的(通过ADL)查询该运算符函数时,编译器将很乐意考虑将a隐式转换为Int<int>,因为我们可以进行隐式转换以匹配常规免费功能。

谈到转化...

  

我写了简单的类并定义了一个副本构造函数。

您没有。那是一个用户定义的构造函数,带有一个int const&参数,而不是像复制构造函数那样的Int<int> const&。您定义了一个转换构造函数(因为它不是显式的),这正是编译器可以将上面的a转换为Int<int>的方式。

  

如果我转身...

在第二个版本中,运算符是模板。 ADL仍在查找它。但是模板参数推导只考虑参数的 exact 类型。也就是说,operator==的两个参数必须能够直接绑定到Int<T> const&并绑定Tint无法直接绑定到Int<int> const&,需要进行转换。因此,它与模板进行模板参数推导所需的参数类型不匹配。因此,该模板无法实例化,因此不是候选模板。

  

这是否意味着朋友功能允许特定的转换?

不,这不是友谊。这是模板业务与非模板业务。您可以定义没有友情的operator==,但是必须对Int进行每个实例化:

template <class T>
class Int {
public:
    T value;
    Int(const T& value_) : value(value_) {
        ;
    }
};

bool operator==(const Int<int>& f, const Int<int>& s) {
    return f.value == s.value;
}

这也会使您的main的格式正确。但是,正如您所注意到的,不必分别声明它们并不是很有用,因此许多代码库都将使用friend版本来自动“注入”该自由函数。