朋友功能和复制构造函数

时间:2014-12-26 23:38:35

标签: c++ templates copy-constructor friend-function

如果在类中定义了友元函数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;
}

5 个答案:

答案 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对象致电BArgument 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";
}