如何初始化类的引用成员变量?

14

考虑以下C++代码:

    #include<iostream>

using namespace std;

class Test {
    int &t;
public:
    Test (int &x) { t = x; }
    int getT() { return t; }
};

int main()
{
    int x = 20;
    Test t1(x);
    cout << t1.getT() << " ";
    x = 30;
    cout << t1.getT() << endl;
    return 0;
}

在使用gcc编译器时,出现了以下错误:

    est.cpp: In constructor ‘Test::Test(int&)’:
    est.cpp:8:5: error: uninitialized reference member ‘Test::t’ [-fpermissive]

为什么编译器不直接调用构造函数?

虽然答案解释了如何解决这个问题,但我想指出的是潜在的问题是初始化实际上发生在进入构造函数体之前,以确保在使用之前所有成员都处于有效状态。由于引用必须被初始化,并且不能在初始化后“重新定位”,因此它们在进入构造函数体之前也需要指向实际变量。 - Justin Time - Reinstate Monica
2个回答

26

这是因为引用只能在初始化列表中进行初始化。使用

Test (int &x) : t(x) {}

解释一下:引用只能被设置一次,这个地方是在初始化列表中完成的。之后,你不能设置引用,但只能给引用的实例赋值。你的代码意味着你试图给一个未经初始化的引用实例赋值,因此它没有引用任何 int 实例,并且你会得到错误信息。


它们也可以通过花括号或等号初始化器进行初始化,尽管这是不常见的用例。 - M.M
如果你需要一个 Test 的默认构造函数,你会怎么做? - Tom Auger
@TomAuger 在类中(或其他地方)添加一个静态的虚拟整型变量,并将引用绑定到它。 - Daniel Frey

3

我的编译器出现了这个错误:

error C2758: 'Test::t' : 必须在构造函数的基类/成员初始化列表中初始化

您需要在初始化列表中对引用进行初始化,这正是必须要做的。:

#include<iostream>

using namespace std;

class Test {
    int &t;
public:
    Test (int &x) : t(x) {  } // <-- initializer list used, empty body now
    int getT() { return t; }
};

int main()
{
    int x = 20;
    Test t1(x);
    cout << t1.getT() << " ";
    x = 30;
    cout << t1.getT() << endl;
    return 0;
}

说明:

如果引用不在初始化列表中,编译器几乎无法检测引用是否已初始化。引用必须被初始化。想象一下这种情况:

Test (int &x, bool b) 
{
   if( b ) t = x;
}

现在构造函数的调用者需要决定是否生成有效的代码。这是不行的。编译器必须确保引用在编译时被初始化。


4
更正一下,t = x 不是引用初始化,而是赋值操作。对于引用来说,这两者非常不同:初始化将引用绑定到对象,赋值则将对象赋给引用所绑定的对象。 - Angew is no longer proud of SO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接