1

让例子是:

class Base {
  Base (const Base & copyFrom) { globalRegister (* this); }
}

class Derived {
  Derived (const Derived & copyFrom) : Base (copyFrom) {}
}

我已经阅读了将 Base 的复制构造函数包含在 Derived 的初始化列表中的建议,以便复制 Base 的属性(如示例中所示)。

但是,我有 Base 的复制构造函数将自身 (* this) 传递给其他对象(要向该对象注册)。那是不是我实际上必须在派生的复制构造函数的初始化列表上使用(隐式或显式)Base的(默认)构造函数,并且仅在派生的复制构造函数的主体中调用Base的复制构造函数,当实际上有一个对象时可以通过 Base 的复制构造函数附加?否则 - (* this) 是一个有效的对象吗?

4

2 回答 2

5

那是不是我实际上必须在派生的复制构造函数的初始化列表上使用(隐式或显式)Base的(默认)构造函数,并且仅在派生的复制构造函数的主体中调用Base的复制构造函数,当实际上有一个对象时可以通过 Base 的复制构造函数附加?

你到底为什么要这么做?
(哦,你不能从派生类的构造函数中调用基类的复制构造函数。只能从它的初始化列表中调用。)

否则 - (* this) 是一个有效的对象吗?

基的初始化列表完成的那一刻,基的所有成员(和基类)都已完全构造。然而,类本身只有在其构造函数完成时才完全构造。
更重要的是,派生类的构造函数还没有启动,所以对象还不是派生类的对象。

所以无论那个注册函数做什么,它都必须考虑到对象的动态类型是base什么,并且它的构造函数还没有完成。(为了安全起见,它所能做的就是将对象的地址存储在某个地方。)

于 2010-11-24T13:53:30.747 回答
1

仅供参考,行为由 C++03 的 § 12.7 2-3 指定:

2) 显式或隐式地将指向 X 类对象的指针(左值)转换为指向 X 的直接或间接基类 B 的指针(引用),X 的构造及其所有直接或间接基类 B 的构造从 B 直接或间接派生的间接基应该已经开始并且这些类的销毁应该没有完成,否则转换会导致未定义的行为。

this是指向 的指针Derived。In Base::Base(),this被隐式转换为 a Base*,这是允许的,因为 Derived 的构造已经开始并且它没有其他派生自 的基Base

§ 12.7 2 继续:

要形成指向对象 obj 的直接非静态成员的指针(或访问其值),obj 的构造应已开始且其销毁不应完成,否则指针值的计算(或访问成员值)导致未定义的行为。

最后,§ 12.7 3 也很重要:

3)成员函数,包括虚函数(10.3),可以在构造或销毁(12.6.2)期间调用。当从构造函数直接或间接调用虚函数时(包括从mem-initializer对于数据成员)或来自析构函数,并且调用应用的对象是正在构造或销毁的对象,调用的函数是在构造函数或析构函数自己的类或其基类之一中定义的函数,但不是函数在从构造函数或析构函数的类派生的类中覆盖它,或在最派生对象的其他基类之一中覆盖它(1.8)。如果虚函数调用使用显式类成员访问(5.2.5)并且对象表达式引用正在构造或销毁的对象,但其类型既不是构造函数或析构函数自己的类也不是其基类之一,则调用未定义。

这两个子句意味着一旦构造函数开始,实例Derived就是一个成熟的实例,尽管它可能处于不一致的状态。BaseBase

于 2010-12-05T06:04:34.977 回答