2015-11-08 72 views
4

好了,它會一點一點技巧。這裏是(簡化)代碼:呼喚的基地之一賦值操作符與C++多重繼承的派生類的虛函數表

class A 
{ 
    virtual ~A(); 
    // fields, none of which has an assignment operator or copy constructor 
}; 

class B 
{ 
    virtual ~B(); 
    // same as A 
}; 

class Derived : public A, public B 
{ 
    Derived(); 
    Derived(const B& b); 
    // no fields 
}; 

隨着Derived::Derived(const B& b)(即接受它的一個基地)如下

Derived::Derived(const B& b) 
{ 
    *static_cast<B*>(this) = b; 
    // Do other stuff with protected fields declared in B 
} 

對我來說,這件事情在「只是避免做這樣」線,但這是一個現有的代碼,我們正在懷疑這個代碼附近有可疑的內存損壞。所以,我很好奇,如果沒關係。

好奇的部分這裏是兩個基類有虛函數表和他們都沒有任何明確的複製/分配構造/運營商。

從我的理解,對於一個Derived類的內存佈局如下

`Derived` 
--------- 
A-vtable 
A-fields 
B-vtable 
B-fields 

,當我調用虛函數,在「B」,宣佈我使用B-vtable,當我打電話一個虛擬函數,在「A」中聲明,我使用的是A-vtable,即vtables沒有合併在一起。

而且從我的理解隱含的複製/賦值構造函數/運營商乙方應隻影響B-fields,當它被稱爲*static_cast<B*>(this) = b;static_cast應該給一個指針開始的B-fields,與B-vtable居住在負從中偏移,據我所知) 。

所以,從我的理解,這個代碼是完全安全的,正確的,雖然不清楚,哈克,但安全。我對麼?是否有任何編譯器特定的怪癖我應該知道(我們在這裏討論MSVC 2012)?

編輯:夥計們,我知道複製構造函數/賦值運算符的區別,非常感謝。這是發生在3次複製構造函數中的事件之一,因爲我監督了它,現在每個答案都會花費一半的文本來告訴完全不相關的問題區別。

+0

「經歷了一個微妙的內存損壞可疑接近這個代碼」 - 去提取小例子呢! –

+0

指針如'this'通常指向隱藏字段,其中V表指針被存儲(即,對象的開始,不與偏移到它),因爲它是用來相當頻繁。指針是否來自靜態投射是無關緊要的。我認爲它也可能是負偏移,這可能是一個實現細節。 –

回答

1

是的,這是正確的。有一種派生類派生到其父母的特殊行爲。當發生多重繼承時,就像你的情況一樣,指針的實際地址可以改變。若要使用exampe:

this      -> | A-vtable | 
           | A-fields | 
static_cast<B*>(this) -> | B-vtable | 
           | B-fields | 

該指針的變化一樣,當你調用從B一個Derived對象導出的函數發生。


但是,要知道,拷貝構造函數是你在該行援引什麼:

*static_cast<B*>(this) = b; 

相反,要調用的B賦值運算符,即B::operator=(const B& other)。如果您沒有定義一個,則使用默認賦值運算符。等號僅在變量聲明的情況下被視爲一個拷貝構造函數:

B newObj = b; 

如果你想實現自己的拷貝構造函數爲Derived,然後顯式調用的B父拷貝構造函數,它試一下:

Derived::Derived(const B& b) : B(b) 
{ 
} 
1

爲什麼不直接調用基類的構造函數?

Derived::Derived(const B& b) 
: B(b) 
{ 
} 

類似的事情可以賦值運算符來完成:

Deriver& Derived::operator=(const Derived& rhs) 
{ 
    A::operator=(rhs); //Assign A's part 
    B::operator=(rhs); //Assign B's part 
    //Derived-specific assignments 

    return *this; 
} 

此操作的首選,安全和完全有效的方法來初始化類的對象,從繼承的東西。

而且,在這一行:

*static_cast<B*>(this) = b; 

你叫賦值運算符,而不是拷貝構造函數。既然你寫了,既沒有定義基本類型,也使用了default(由編譯器生成)。

我不明白爲什麼你甚至想到vtable。這是使用編譯器生成的拷貝構造函數和賦值操作符的類的簡單繼承。一切都很簡單,可以沒有任何黑客:)做

+0

這不是我的代碼,我通常完全避免繼承,拋開多重繼承。我知道還有其他方法可以在沒有黑客的情況下做到這一點,但問題不在於此。問題是關於 - 這種方式是否安全。但是,無論如何,我想知道是否打電話給一個完全合格的運營商也會這樣做。 –

相關問題