【发布时间】:2016-06-08 15:30:01
【问题描述】:
EDIT1:已编辑问题以修复 Yakk 答案中指出的 UB(这是关于原始问题的有效答案)。
考虑以下代码:
class C
{
protected:
C(bool) : c(0) { s = new char[10]; /* init C members... */ }
void cleanup() { delete[s]; /* cleanup C members... */ } //EDIT1
C() { /* do nothing, keep C members unchanged */ }
// EDIT1: removed dtor: ~C() { /* do nothing, keep C members unchanged */ }
// EDIT1: implicitly defined default (trivial) dtor
int c;
char* s;
};
class Child1 : public C
{
public:
Child1(bool) : C(true) { }
void cleanup() { C::cleanup(); } //EDIT1
Child1() { c ++; }
// EDIT1: removed dtor: ~Child1() { }
// EDIT1: implicitly defined default (trivial) dtor
};
class Child2 : public C
{
public:
Child2() { c --; }
void cleanup() { C::cleanup(); } //EDIT1
// EDIT1: removed dtor: ~Child2() { }
// EDIT1: implicitly defined default (trivial) dtor
};
int main()
{
char storage[sizeof(Child1)]; // (0) storage for any C child instance
C* child = new(&storage) Child1(true); // (1) create in-place Child1 instance and initialize C members
//EDIT1: removed: static_cast<Child1*>(child)->~Child1(); // (2) destroy Child1 instance, keeping C members unchanged
child = new(&storage) Child2; // (3) create in-place Child2 instance, keeping C members unchanged, overwritting Child1 members
//EDIT1: removed: static_cast<Child2*>(child)->~Child2(); // (4) destroy Child2 instance, keeping C members unchanged
child = new(&storage) Child1(true); // (5) create in-place Child1 instance, keeping C members unchanged, overwritting Child2 members
//EDIT1: removed: static_cast<Child1*>(child)->~Child1(); // (6) destroy Child1 instance, keeping C members unchanged
child->cleanup(); // (7) cleanup Child1 & C members [EDIT1]
return 0;
}
- 在第 (1) 行,
Child1实例是使用非默认 ctorChild1(bool)“就地”创建的。这导致通过非默认 ctorC(bool)初始化父类C成员。 -
在第 (2) 行,[EDIT1]Child1实例被销毁。这将调用父类C的dtor,为了保持C成员不变,它自愿实现为空。 - 在第 (3) 行,
Child2实例是使用默认 ctorChild2“就地”创建的。这覆盖了 Child1 实例[EDIT1] 并调用父类C的 default-ctor,为了保持C成员不变,它自愿实现为空。
在这一步,Child2 实例已经能够访问父类 C 受保护的成员,保持不变尽管第 (3) 行。 [编辑1]Child1 实例在执行的覆盖操作中已被销毁
上述模式使我能够实现我的主要目标:创建 并销毁[EDIT1] 类C 的任何子类的实例,保持C 成员不变。此外,使用非默认 ctor,我有办法初始化 C 成员(例如在第 (1) 行)。
但是,这种模式有几个缺点:
类C成员不能是 const 或引用,并且必须具有平凡的默认 ctor 和 dtor。 (同样的规则适用于任何子成员。)-
清理析构函数不容易实现(如果 C++ 支持非默认 dtor,它可能与初始化非默认 ctorC(bool)相同,但遗憾的是 C++ 不支持。 - class
C成员不能是 const 或引用。 [编辑1] -
C类、C类的父类和C类成员必须有一个明确定义的默认 ctor 实现为空(即类似琐碎)[EDIT1] -
C类必须有一个微不足道的 dtor。 [编辑1]
我的问题:
- 是上面描述的模式定义的行为?[EDIT1]
- 是否有任何其他方法可以实现相同的目标(
[in-place][EDIT1] 创建并销毁[EDIT1] 父类的子类实例 @ 987654346@,保持父类C成员不变)没有上面列出的缺点(尤其是第一个)[EDIT1]?
理想情况下,如果我有办法防止父类 [EDIT1]C ctor 和 dtor 在子构造/销毁过程中被调用,这将是完美的。
注意1:在实际应用中,C类可能很大,C子类的构造/destruction[EDIT1]必须密集发生;就地构造旨在优化此类操作的性能。
注意2[EDIT1]:类C 和children 中的琐碎dtor 需要在错误调用析构函数的情况下防止未定义行为;根据 C++ 标准的 §3.8/1,当调用析构函数时,具有平凡 dtor 的对象的生命周期不会结束。
【问题讨论】:
标签: c++ inheritance c++14