是否存在C++對象切片效果的任何示例,這些示例可能導致未定義的行爲,內存泄漏或其他正確的代碼集崩潰?例如,當類A
和B
(從A
繼承)是正確和可靠的,但調用void f(A a)
明顯會導致令人討厭的事情。導致泄漏/未定義的行爲/崩潰的C++切片
它是需要形成一個測試問題。目標是要知道參與者是否意識到切片現象,使用一個正確性不應該成爲意見的示例代碼片段。
是否存在C++對象切片效果的任何示例,這些示例可能導致未定義的行爲,內存泄漏或其他正確的代碼集崩潰?例如,當類A
和B
(從A
繼承)是正確和可靠的,但調用void f(A a)
明顯會導致令人討厭的事情。導致泄漏/未定義的行爲/崩潰的C++切片
它是需要形成一個測試問題。目標是要知道參與者是否意識到切片現象,使用一個正確性不應該成爲意見的示例代碼片段。
如果A
確實是「正確無誤的」,那麼切片(複製基礎子對象)定義良好,不會導致您提到的任何問題。如果您希望副本的行爲類似B
,則它會導致的唯一問題是意外行爲。
如果A
不能正確複製,則切片將導致複製該類型對象時出現的任何問題。例如,如果它有一個析構函數,用於刪除由對象持有的指針,並且複製創建了一個指向同一事物的新指針,那麼當兩個析構函數刪除相同的指針時,您將獲得未定義的行爲。這不是切片本身的問題,而是切片對象的無效複製語義。
你總是可以構建這樣一個例子
struct A {
A() : invariant(true) {}
virtual void do_sth() { assert(invariant); }
protected:
bool invariant;
};
struct B : A {
B() { invariant=false; }
virtual void do_sth() { }
};
void f(A a)
{
a.do_sth();
}
當然,這可以防止內部A
,當拷貝構造函數/賦值運算符不檢查是否不變的是真實的。
如果不變量比我的布爾值更隱含,這些東西可能非常棘手。
我在這裏看不到任何未定義的行爲 – 2012-11-28 13:39:23
* 1 *這不是對象切片,因爲'B'沒有新的數據被切掉。* 2 *除非你用'B'參數調用'f(A)',否則我看不出你的代碼有什麼問題。 – Walter
@Walter:用'B'參數調用'f(A)'正是問題出現的地方:'B'被切片爲'A',然後失敗了'A :: do_sth'中的斷言。 –
如果您通過指針或對其基類的引用來操作派生類,則對象切片實際上只是一個問題。然後,派生類的附加數據保持不變,而基本部分的附加數據可能會被修改。這可能會破壞派生類的不變量。舉個簡單的例子,參見http://en.wikipedia.org/wiki/Object_slicing
但是,我會認爲這是一個設計缺陷(派生類)。如果通過任何合法的方法來訪問一個類,包括那些作爲基類的指針或引用參數,都可以破壞它的不變量,那麼這個類就會被設計的很糟糕。避免這種情況的一種方法是聲明基地private
,以便派生類不能通過其基地合法訪問。
一個例子是:
class A
{
int X;
A(int x) : X(x) {}
void doubleX() { X+=X; }
/* ... */
};
class B : public A
{
int X_square;
B(int x) : A(x), X_square(x*x) {}
/* ... */
};
B b(3);
B.doubleX(); /// B.X = 6 but B.X_square=9
從這個例子也很明顯,這是B.簡單的設計缺陷,在這個例子中,提供
void B::doubleX() { A::doubleX(); X_squared=X*X; }
不能解決問題,如
A&a=b;
a.doubleX();
仍然打破不變。這裏唯一的解決方案是宣佈基地A
私人或更好地使A
私人成員,而不是基地B
。
好的。那麼有關測試某人意識的任何提示? – Notinlist