編輯1:編輯問題以修復在雅克答案中指出的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
實例是 '就地' 使用非默認構造函數Child1(bool)
創建。這導致通過非默認的ctorC(bool)
初始化父類C
成員。 在第(2)行,[EDIT1]Child1
實例被銷燬。這將調用母類C
的驅動程序,它自願實現爲空,以保持C
成員不變。- 在第(3)行,使用
Child2
的默認值ctor創建了一個Child2
實例。此覆蓋Child1實例 [EDIT1],並調用父類C
的默認值ctor,該值自動爲空,以保持C
成員不變。
在此步驟中,Child2
情況下已經能夠訪問父類C
保護成員,保持不變雖然(3)。 [EDIT1]Child1
實例已在生產線上進行的重寫操作被破壞
上述模式可以讓我實現我的主要目標:創建和銷燬 [EDIT1]的情況下,保持C
類的任何子女的C
理事國不變。此外,使用非默認ctor,我有一種方法來初始化成員(例如在第(1)行)。
然而,這種模式有幾個缺點:
類C
成員不能是const或引用,並且必須具有平凡缺省構造函數和析構函數。 (同樣的規則適用於任何子成員。)清理析構函數不易實現(它可能與初始化非默認ctorC(bool)
相同,如果C++支持非默認的dtor,但遺憾的是C++沒有。- 類
C
成員不能是const或參考。[EDIT1] - 類
C
,C
類的父,和類C
成員必須具有顯式定義的默認構造函數實現爲空(即瑣碎狀)[EDIT1] - class
C
必須有一個微不足道的。[EDIT1]
我的問題:
- 是上述定義的操作描述的模式[EDIT1]
- 是否有任何其他的方式來達到同樣的目標(
[就地? ][EDIT1]創建並銷燬[EDIT1]父類的子類實例C
,保留父類C
成員不變)沒有缺陷(特別是第一個)[EDIT1]上面列出的?
理想的情況下,如果我有一個方法,以防止在孩子建造/銷燬過程被調用父類的構造函數 [EDIT1]C
和析構函數,這將是完美的。
注1:在實際應用中,C
類可能相當大,建設 /銷燬 [EDIT1]的C
孩子已經集中出現;就地建設旨在優化這些操作的性能。
注2 [EDIT1]:類C
中的微不足道的小孩,在錯誤地調用析構函數的情況下,兒童需要防止未定義的行爲;根據C++標準的§3.8/ 1,當調用析構函數時,具有微不足道的對象的生命期不會結束。
感謝您的回答,以及您在我的計劃中指出的UB。我更新了我的問題(和我的計劃)以擺脫UB。您提出的作爲替代解決方案的「手動繼承方案」看起來很棒,但實施和使用有點棘手;儘管如此,我會更深入地研究它。非常感謝。 – shrike