简体   繁体   English

派生类的副本构造函数(C ++)的初始化列表上的基类

[英]Base class on the initialisation list of a derived class' copy constructor (C++)

Let the example be: 让示例为:

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

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

I've read suggestions to include the Base's copy constructor on the initialisation list of Derived in order to copy over the Base's properties (as in the example). 我已经阅读了一些建议,以便将Base的副本构造函数包括在Derived的初始化列表中,以便复制Base的属性(如示例中所示)。

However, I have the Base's copy constructor passing itself (* this) to other object (to be registered with that object). 但是,我有Base的副本构造函数将自身(*此)传递给其他对象(向该对象注册)。 Would that be a case where I actually must use (implicitly or explicitly) Base's (default) constructor on the initialisation list of Derived's copy constructor, and call the Base's copy constructor only in the body of Derived's copy constructor, when there is actually an object that can be attached by Base's copy constructor? 在实际存在对象的情况下,实际上我必须在Derived的复制构造函数的初始化列表上使用(隐式或显式)Base的(默认)构造函数,并且仅在Derived的复制构造函数的主体中调用Base的复制构造函数的情况可以由Base的复制构造函数附加? Else - is (* this) a valid object? 否则-(*这)是有效的对象吗?

Would that be a case where I actually must use (implicitly or explicitly) Base's (default) constructor on the initialisation list of Derived's copy constructor, and call the Base's copy constructor only in the body of Derived's copy constructor, when there is actually an object that can be attached by Base's copy constructor? 在实际存在对象的情况下,实际上我必须在Derived的复制构造函数的初始化列表上使用(隐式或显式)Base的(默认)构造函数,并且仅在Derived的复制构造函数的主体中调用Base的复制构造函数的情况可以由Base的复制构造函数附加?

Why on earth would you want to do that? 您到底为什么要这样做?
(Oh, and you can not call a base class' copy constructor from a derived class' constructor's body . Only from its initialization list.) (哦,您不能从派生类的构造函数的主体中调用基类的副本构造函数。只能从其初始化列表中调用。)

Else - is (* this) a valid object? 否则-(*这)是有效的对象吗?

The moment the base's initialization list has completed, all of base's members (and base classes) are fully constructed. 基数的初始化列表完成后,基数的所有成员(和基类)均已完全构建。 The class itself, however, is only fully constructed when its constructor has finished. 但是,类本身仅在构造函数完成后才完全构建。
More importantly, the derived class' constructor hasn't even started yet, so the object is not a derived class' object yet. 更重要的是,派生类的构造函数甚至还没有开始,因此该对象还不是派生类的对象。

So whatever that registering function does, it has to take into account that the object's dynamic type is base and that its constructor hasn't finished yet. 因此,无论该注册函数执行什么操作,都必须考虑到该对象的动态类型是base类型,并且其构造函数尚未完成。 (To be safe, all it can do is to store the object's address somewhere.) (为了安全起见,它所能做的就是将对象的地址存储在某个位置。)

Just for reference, the behavior is specified by § 12.7 2-3 of C++03: 仅供参考,该行为由C ++ 03的§12.7 2-3指定:

2) To explicitly or implicitly convert a pointer (an lvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. 2)要将表示X类对象的指针(左值)显式或隐式转换为X的直接或间接基类B的指针(引用),X的构造及其所有直接或间接的构造直接或间接从B派生的间接基础将已经开始,并且这些类的销毁还没有完成,否则转换将导致不确定的行为。

this is a pointer to Derived . this是指向Derived的指针。 In Base::Base() , this is implicitly cast to a Base* , which is allowed because the construction of Derived has started and it has no other bases that derive from Base . Base::Base()this其隐式转换为Base* ,这是允许的,因为Derived的构造已经开始,并且没有其他可从Base派生的Base

§ 12.7 2 continues: 第12.7 2节继续:

To form a pointer to (or access the value of) a direct nonstatic member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior. 为了形成指向对象obj的直接非静态成员的指针(或访问其值),应开始obj的构造,并且其销毁还应完成,否则将计算指针值(或访问成员值)导致未定义的行为。

Finally, § 12.7 3 is also important: 最后,§12.7 3也很重要:

3) Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). 3)成员函数,包括虚拟函数(10.3),可以在构造或销毁过程中调用(12.6.2)。 When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructor's own class or in one of its bases, but not a function overriding it in a class derived from the con- structor or destructor's class, or overriding it in one of the other base classes of the most derived object (1.8). 当从构造函数(包括从数据成员的mem-initializer )或析构函数直接或间接调用虚函数,并且调用所应用的对象是正在构造或销毁的对象时,所调用的函数是一个在构造函数或析构函数自己的类中或在其基类之一中定义的函数,但不是在从构造函数或析构函数的类派生的类中覆盖它的函数,或在大多数派生对象的其他基类之一中覆盖它的函数(1.8)。 If the virtual function call uses an explicit class member access (5.2.5) and the object-expression refers to the object under construction or destruction but its type is neither the constructor or destructor's own class or one of its bases, the result of the call is undefined. 如果虚拟函数调用使用显式的类成员访问(5.2.5),并且object-expression表示正在构造或销毁的对象,但其类型既不是构造函数或析构函数自己的类,也不是其基类之一,则结果为通话未定义。

These two clauses means an instance of Derived is a fully-fledged Base once a Base constructor begins, though it might be in an inconsistent state. 这两个子句表示,一旦Base构造函数开始,尽管Derived实例处于完全不一致的状态,但它是成熟的Base

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM