【问题标题】:Reference member variable initialization error with default constructor使用默认构造函数引用成员变量初始化错误
【发布时间】:2017-07-19 17:14:38
【问题描述】:

我知道要初始化类中的引用成员变量,我必须使用初始化器列表,使用参数化构造函数来初始化成员变量。 我也知道不需要默认构造函数。

问题:

  1. 但我不明白为什么定义默认构造函数会引发编译错误? 编译器是否不够聪明,无法在以下情况下考虑参数化构造函数而不是抛出错误?

  2. 如果上述问题有令人信服的答案,那么为什么编译器会允许声明默认构造函数(没有定义)?它在这里有什么不同?

class SomeClass
{
public:
    //SomeClass(){} //THIS IS AN ISSUE
    //SomeClass();  //THIS IS FINE THOUGH


    SomeClass(int j):i(j){}
    int& i;

};
int main()
{

    SomeClass obj(2);
    return 0;
}

我相信 const 成员函数的行为也是如此。引用和 const 成员变量的原因是否相同?

【问题讨论】:

  • 您可能还想重新考虑拥有一个参考成员 - 这不是一个好主意。

标签: c++ reference


【解决方案1】:

为什么定义默认构造函数会引发编译错误?

不是你定义了默认构造函数,而是默认构造函数的定义没有初始化i。您需要初始化所有引用的成员变量,而您的空定义不会这样做。

这与您需要初始化引用变量的原因相同:

void foo() {
    int &i; // error: declaration of reference variable 'i' requires an initializer
}

为什么编译器允许声明默认构造函数(没有定义)

因为定义是问题所在,而不是声明。例如,将格式错误的构造函数定义移到类定义之外会产生同样的错误:

class SomeClass
{
public:
    SomeClass();
    int &i;
};

SomeClass::SomeClass() {} // error: constructor for 'SomeClass' must explicitly initialize the reference member 'i'

这两个示例的唯一问题是您没有初始化 i

注意以下示例,这些示例将编译。请注意,构造函数的声明没有改变,但定义确实初始化了i

int someGlobalInt;

class SomeClass
{
public:
    SomeClass() : i(someGlobalInt) {}
    int &i;
};

int someGlobalInt;

class SomeClass
{
public:
    SomeClass();
    int &i;
};

SomeClass::SomeClass() : i(someGlobalInt) {}

【讨论】:

  • 好吧,问题更多的是:_当我已经提供了一种通过参数化构造函数初始化成员变量的方法时,为什么还要寻找默认构造函数?此外,在存在参数化构造函数的情况下,如果不允许定义默认构造函数,那么为什么还要允许声明默认构造函数呢? _
  • @anurag86 "如果不允许定义默认构造函数,则存在参数化构造函数" -- 默认构造函数的定义允许 ,您刚刚提供了一个格式错误的定义,因为它没有初始化i如果您完全删除参数化构造函数,您将遇到相同的错误。
【解决方案2】:

编译器要求初始化所有引用。如果你定义了一个什么都不做的默认构造函数,那么编译器就会报错,因为你没有初始化i。如果您声明默认构造函数,您还没有定义它,所以编译器没有问题。考虑一下:

class SomeClass
{
    SomeClass(); // Compiler is fine with this
    ...
};

int someInt;
SomeClass::SomeClass(): i(someInt) {} // OK - i is initialized

您稍后定义了构造函数并初始化了i

【讨论】:

  • 如果是这样,那为什么还要允许声明呢?
  • @anurag86 为什么不呢?您可能稍后想要派生 SomeClass 并使用自定义初始化器列表调用基类的默认 ctor。
  • @anurag86 因为编译器只关心定义。当它只有声明时,它不知道你是否会初始化引用
【解决方案3】:

第一个是构造函数的实现,它未能完成所需的引用成员初始化:
SomeClass(){}

第二个只是一个构造函数的声明。只要它不被执行,缺乏执行就不是问题。并且只要未实施(可能)初始化失败就不是问题:
SomeClass();

请注意,非参数化构造函数可以正确初始化引用成员,例如对全局或静态变量的引用。这可能对任何事情都没有用,但这是可能的。所以对于编译器来说,第二个版本不是直接的问题,也不一定表明其他地方存在实际问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-03
    • 2011-08-09
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多