通过友元类访问私有构造函数

access to private constructor by friend class

本文关键字:构造函数 访问 友元      更新时间:2023-10-16

问题:源代码(见下文)编译为MSVC,但不编译g++。

#include <iostream>
using namespace std;
class B;
class A
{
friend class B;
private:
    int i;    
    A(int n) : i(n) { }
public :
    A(A& a) {   if (&a != this) *this = a;  }
    int display() { return i;}
};
class B
{
public :
    B() { }
    A func( int j)  {  return A(j); }
};
int main(int argc, char **argv)
{
    B b;
    A a(b.func((10)));
    cout << " a.i = " << a.display() << endl;
    return 0;
}

输出:

GNU g++ compilation message:
    g++ -c main.cpp
    main.cpp: In member function 'A B::func(int)':
    main.cpp:25:38: error: no matching function for call to 'A::A(A)'
             A func( int j)  {  return A(j); }
                                          ^
    main.cpp:25:38: note: candidates are:
    main.cpp:17:9: note: A::A(A&)
             A(A& a) {   if (&a != this) *this = a;  }
             ^
    main.cpp:17:9: note:   no known conversion for argument 1 from 'A' to 'A&'
    main.cpp:14:9: note: A::A(int)
             A(int n) : i(n) { }
             ^
    main.cpp:14:9: note:   no known conversion for argument 1 from 'A' to 'int'
    main.cpp: In function 'int main(int, char**)':
    ...

为什么? Class Bclass A friend,然后B可以访问私有构造函数A(int i)

复制构造函数必须采用const引用,以便它可以绑定到临时A

 A(const A& a) { .... }

C++ 标准不允许将非常量引用绑定到临时引用。 g++对此很严格,而MSVC有一个打破规则的"扩展"。

除此之外,复制构造函数的实现看起来很奇怪。您不应该在那里使用赋值运算符。对于像 A 这样的类,你应该使用隐式生成的复制构造函数,换句话说,删除你自己的:

class A
{
  friend class B;
private:
    int i;    
    A(int n) : i(n) { }
public :
    int display() const { return i;}
};

这是MS VC++的一个错误。它不应编译代码。问题是g++的错误消息不够明显。

事实上,编译器试图避免使用复制构造函数,并使用构造函数 A(int n); 直接在"a"中构建对象。但是,应该有一个合适的复制构造函数可用。由于应该复制临时对象(如果不使用ilision),因此复制构造函数应具有对对象的const引用。而不是A(A&a);您的复制构造函数应声明为 A( const A&a);如果你要进行更改,那么 g++ 将编译代码。

为示例定义复制构造函数的最简单方法是编写

A( const A & ) = default;

但是,我不确定您的MS VC ++编译器是否支持此功能。