使用初始化列表中的引用初始化对象成员

Initialize object member with reference in initialization list

本文关键字:初始化 引用 对象 成员 列表      更新时间:2023-10-16

我这样做对吗?这是我代码的高度简化版本:

class Logger {
   public:
      Logger(std::ostream) { /*...*/}
};
class Driver {
public:
   Driver() : m_logger(std::cout) {}
   Driver(Logger& logger) : m_logger(logger) {}
private
   Logger m_logger;
};

所以我的类Driver有一个类型为Logger的成员。当我调用无参数构造函数Driver()时,Driver的实例会使用std::cout创建自己的Logger实例。

调用Driver(Logger)时,实例应使用已存在的Logger实例作为引用。

上面的代码使用g++编译。虽然我理解调用Driver()时会发生什么,但我不明白调用Driver(Logger)时会发生怎样的情况。Logger没有接受对Logger的引用作为参数的构造函数("复制构造函数")。那么调用Driver(Logger)时执行了什么呢?

除非您自己声明,否则Logger的一个普通复制构造函数是为您合成的

这与为您合成普通默认构造函数的方式非常相似(如果您没有声明默认用户定义构造函数)。


[C++11: 12.8/7]:如果类定义没有显式声明复制构造函数,则隐式声明一个如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数定义为已删除;否则,它被定义为默认值(8.4)。如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不赞成使用后一种情况。因此,对于类定义

struct X {
   X(const X&, int);
};

复制构造函数是隐式声明的。如果用户声明的构造函数后来被定义为

X::X(const X& x, int i =0) { /* ... */ }

则CCD_ 16的复制构造函数的任何使用都是由于歧义而形成的;不需要进行诊断。

[C++11: 12.8/8]:X的隐式声明的复制构造函数的形式为

X::X(const X&)

如果

  • X的每个直接或虚拟基类B具有复制构造函数,该复制构造函数的第一参数是类型const B&const volatile B&,以及
  • 对于类类型为M(或其数组)的X的所有非静态数据成员,每个此类类类型都具有第一参数为const M&const volatile M&类型的复制构造函数

否则,隐式声明的复制构造函数将具有形式

X::X(X&)

当您使用Logger参数构造Driver时,它将被引用,并调用Logger副本构造函数来初始化m_logger,因此您最终得到一个新的Logger,它是该参数的副本。复制构造函数由编译器提供,除非通过声明复制构造函数private显式使Logger不可复制。

似乎完全有效,只是您应该将logger参数作为const引用;毕竟,你要复制它,而不是修改它。