2010-08-05 36 views
2

我們在共享庫的版本1的結構體,我們需要保持的ABI:維護ABI:添加構造函數結構

struct Person 
{ 
    std::string first_name; 
    std::string last_name; 
} 

在第2次修訂,我們正在改變人到這一點:

class Person 
{ 
public: 
    Person(const std::string &f, const std::string &l); 

    std::string first_name; 
    std::string last_name; 
} 

爲了保持源代碼兼容性,我們想改變人的逆轉1,使代碼編譯反對新的頭文件將運行和代碼重新編譯不能運行。

我們可以用兩個新的非內聯的構造函數如下:

class Person 
{ 
public: 
    Person(); 
    Person(const std::string &f, const std::string &l); 

    std::string first_name; 
    std::string last_name; 
} 

我們正在做的這一切都與G ++。在使用nm查看生成的共享庫時,我沒有看到普通結構的構造函數或析構函數,所以我猜測那些沒有重新編譯的代碼只會像前面那樣在調用站點構造Person。任何重新編譯的代碼都將使用無參數構造函數。

我看到的唯一問題是,如果我們需要回滾到沒有構造函數的共享庫的較舊版本,那麼編譯的任何代碼都會中斷,但我並不擔心這種情況。

回答

2

我認爲它應該工作,假設你明確的默認ctor和以前使用的隱式ctor做的是一樣的事情。在這個簡單的例子。然而,恕我直言很難預測或知道編譯器會做/改變什麼。我不會相信它,我寧願重新編譯圖書館用戶,如果我是你的話。

2

它可能「有效」,但是您將打破「一個定義規則」,並且就C++標準而言,您將在Undefined Behavior land中關閉,這不是一個好地方。

+0

更多關於「不是好地方」 – 2010-08-05 22:38:07

3

以下情況如何?

class NewPerson : public Person 
{ 
public: 
    NewPerson(const std::string &f, const std::string &l) 
    { 
     first_name = f; 
     last_name = l; 
    } 
} 
+0

這是一個非常好的主意(與其他人相比)。 :-) – 2010-08-05 22:36:53

+0

除非他有某個人的數組或矢量,或者正在使用Person值,我可能會偷偷摸摸地懷疑。 – 2010-08-05 23:11:01

+0

是的,我們實際上有一個「Person」的向量,它們只是一堆用於數據庫查詢的參數,這就是爲什麼我們不關心結構設計的原因。 – 2010-08-06 00:36:40

1

在不破壞二進制兼容性的情況下向類或結構中添加新的非虛函數應該沒問題。這是因爲類函數是以一個隱含的this作爲其第一個參數的普通函數實現的。

但是,如果添加新的虛擬函數,則可能會破壞兼容性,因爲新函數將強制修改vtable,從而可能破壞兼容性。

因此,添加額外的構造函數(永遠不會是虛擬的)不會破壞兼容性。如果你要添加一個虛擬析構函數,你很可能會破壞兼容性。

+0

說的是誰?實施細節和ABI因此完全落實到實施中。如果你打算說它沒有打破它們,你最好說出你正在談論的編譯器版本和操作系統。由於舊代碼使用編譯器生成的默認構造函數,而新代碼具有用戶定義的構造函數。誰說這些具有相同的ABI。 – 2010-08-05 22:41:05

+0

@Martin,標準對ABI的問題沒有提及,所以在技術上你是正確的。但是我挑戰你找到一個以任何其他方式實現非虛函數的C++ ABI。 – doron 2010-08-05 22:56:23

+0

@馬丁,這是否甚至重要?只要類的二進制佈局相同,那麼Person是如何構造的,無論是在調用代碼中還是通過構造函數內聯? – 2010-08-06 00:35:08