如果在类中定义了友元函数mag(),则下面显示的代码不会编译,但如果在类外部定义(注释)则可以工作。我认为差异是由用于将参数类型从A更改为B的复制构造函数引起的。有人可以解释为什么我应该在外面定义友元函数吗?
此外,如果B类是模板类(在顶部添加template <class T>
),则在外部定义友元函数也不起作用。
#include <iostream>
using namespace std;
class A {
};
class B {
public:
B(const A& p) {
std::cout << "Copy/Conversion constructor" << std::endl;
}
friend void mag(const B& p) {
std::cout << "Mag Inside`.\n";
}
};
//void mag(const B& p) {
// std::cout << "Mag Outside.\n";
//}
int main() {
A a;
mag(a);
return 0;
}
答案 0 :(得分:4)
因为函数mag
在全局范围内不是声明(当你同时将它作为朋友时,你确实定义并声明了它,但声明在它自己的范围内仍然需要)。
您需要声明:
class B {
public:
B(const A& p) {
std::cout << "Copy constructor" << std::endl;
}
friend void mag(const B& p) {
std::cout << "Mag Inside`.\n";
}
};
void mag(const B& p);
如果您使用mag
对象致电B
,Argument Dependant Lookup会查看B
的范围并找到定义。
现在,如果B
是模板,则需要使用适当的参数声明每个版本的mag
(如果存在多个版本,则需要帮助编译器解决模糊过程中的歧义问题。转换):
template<typename T>
class B {
public:
B(const A& p) {
std::cout << "Copy constructor" << std::endl;
}
friend void mag(const B<T>& p) {
std::cout << "Mag Inside`.\n";
}
};
void mag(const B<int>& p); // Version for B<int> declared.
答案 1 :(得分:2)
与此问题相关的C ++草案标准N3337的部分:
11.3朋友
4在朋友声明中首先声明的函数具有外部链接(3.5)。否则,该函数将保留其先前的链接(7.1.1)。
6当一个类的友元声明中可以定义一个函数,当且仅当该类是非本地类(9.8),函数名称是非限定的,并且该函数具有命名空间作用域。 [示例:
class M { friend void f() { } // definition of global f, a friend of M, // not the definition of a member function };
- 结束示例]
7这样的函数是隐含的
inline
。在类中定义的友元函数位于定义它的类的(词法)范围内。在课外定义的朋友函数不是(3.4.1)。
在您的示例中,mag
在类B
的词法范围中定义,即名称mag
在类外部不可见,即使它具有外部链接。要使该功能在课程B
之外可见,必须在B
之外声明。
答案 2 :(得分:0)
mag
未在全局范围内声明。此外,ADL在函数重载解析的情况下启动,但它严格基于参数的类型 - 而不是implicity-convertible类型。如果您想使用ADL,请使用mag
。
B
int main() {
A a;
mag(B(a));
return 0;
}
答案 3 :(得分:0)
如果该类是模板,则无法为类定义朋友函数,因为:
假设您有B<int>
和B<float>
,那么编译器是否将B视为B<int>
或B<float>
因此你必须将mag声明为模板,如下所示:
// Inside the class :
friend void mag(const B<T>& p);
// Outside the class :
template <typename T> void mag(const B<T>& p) {
std::cout << "Mag Outside.\n";
}
然后它会起作用!
答案 4 :(得分:0)
1。 如果类B不是模板类,则必须在类外定义mag函数,因为它是友元函数,这意味着它是非类成员函数。
class B{
public:
B(const A& p){
cout<<"copy constructor"<<endl;
}
friend void mag(const B& p);
private:
int k;
};
void mag(const B& p){
cout<<"mag"<<endl;
}
2。 如果B类是模板类,则应添加模板&lt; ...&gt;函数声明和定义中的语句。
template<class T>
class B{
public:
B(const T& p){
cout<<"copy constructor"<<endl;
}
template<class T2> //declare mag as a template function
friend void mag(const T2& p);
};
template<class T> //define mag function
void mag(const T& p){
cout<<"mag\n";
}