2016-07-22 22 views
2

我遇到了對象切片的奇怪情況。我正在處理需要單例類的項目,所以我的基類和派生類都是單例類。以下示例案例描述了我的情況。對基類靜態引用數據成員的C++對象切片行爲的奇怪情況

這是我的基類

// Base.h 
class Base 
{ 
    public: 

     static Base& base; 

     virtual void doSomething(){ cout<<"Base Do Something"<<endl; } 

    protected: 

     Base(); 
     virtual ~Base(); 
     static Base& getBaseInstance(); 

    private: 
}; 

//Base.cpp 
Base::Base() 
{ 
    //ctor 
} 

Base::~Base() 
{ 
    //dtor 
} 

Base& Base::getBaseInstance() 
{ 
    static Base object; 
    return object; 
} 
Base& Base::base=Base::getBaseInstance(); 

這是我的派生類

class Derived: public Base 
{ 
    public: 

    static Derived& derived; 
    virtual void doSomething(){ cout<<"Derive Do Something"<<endl; } 

    static Derived& getDerivedInstance(); 
    protected: 
     Derived(); 
     virtual ~Derived(); 

    private: 
}; 

Derived::Derived() 
{ 
    //ctor 
} 

Derived::~Derived() 
{ 
    //dtor 
} 

Derived& Derived::derived=Derived::getDerivedInstance(); 

Derived& Derived::getDerivedInstance() 
{ 
    static Derived object; 
    return object; 
} 

最後,這是我的主要功能

int main() 
{ 
    cout << "Hello world!" << endl; 
    Base::base.doSomething(); 
    Derived::derived.doSomething(); 

    Base::base=Derived::derived; 

    Base::base.doSomething(); 

    Base::base=Derived::getDerivedInstance(); 

    Base::base.doSomething(); 

    Base& r = Derived::derived; 

    r.doSomething(); 

    Base::base=Derived::getDerivedInstance(); 
    Base::base.doSomething(); 
    return 0; 
} 

而且我正在爲這個下面的輸出

Hello world! 
Base Do Something 
Derive Do Something 
Base Do Something 
Base Do Something 
Derive Do Something 
Base Do Something 

所以我的問題是因爲對象切片不應該在引用上工作,那麼爲什麼我不能覆蓋Base::base引用我創建爲帶有Derived對象的基類的靜態數據成員?雖然這工作正常Base& r = Derived::derived;

我的意思是當我打電話做一些事情r.doSomething()我得到doSomething派生類。但事實卻不是這樣與

Base::base=Derived::derived;  
    Base::base.doSomething(); 

Base::base=Derived::getDerivedInstance();  
    Base::base.doSomething(); 

任何類型的澄清將不勝感激。 謝謝。

+0

您不能辭職。如果它看起來像你那麼正在發生的是切片。 –

+0

謝謝隊友。我犯了這樣一個愚蠢的錯誤(自2晚以來的編碼,我想我應該睡覺)再次感謝。 –

回答

3

當你

Base::base=Derived::derived; 

您沒有設置基準參考來引用派生類。這是賦值運算符,它所做的全部是將derivedBase部分與base對齊。

base仍然Base型的,從來沒有改變,因爲引用永遠只能初始化一次,你做到這一點與

Base& Base::base=Base::getBaseInstance(); 

如果你想要這個再分配行爲,你將需要使用一個指針類型。

+0

哦,我完全忘記了只能初始化一次引用的事實。再次感謝。 –

+1

@ Dr.Xperience沒問題。樂意效勞。 – NathanOliver

1

引用是爲了所有目的引用的對象。分配給參考是分配給參考的對象。在你的情況下,對象沒有數據成員,所以沒有任何影響。

特別是沒有可檢測到的切片。

聲明

Base& r = Derived::derived; 

&hellip;是一個非常不同的情況:初始化,而不是分配。

初始化使引用引用指定的對象。

此後無法更改參考。


其他消息:

  • 全局變量(引用)運行靜態初始化順序的悲劇的風險。它們只是爲了消除單身吸氣劑功能的優點。對於全局函數,這些函數只是沒有用處而增加了詳細程度。

  • 具有數據成員的可變單例允許在代碼的廣泛分離和看似沒有連接的部分之間進行通信。這使得很難依賴關於當前狀態的任何假設以及什麼影響什麼。這也是爲什麼在每種編程語言中全局變量都被認爲是邪惡的™,所以謹慎使用單例。

+0

這只是一個例子。我的實際案例在派生類中有很多成員。感謝幫助。我犯了這樣一個愚蠢的錯誤。 –

+0

我的項目只有兩個單身人士。他們充當服務提供者。儘管對於驅動程序服務提供商來說,開銷很大。 –

1

Base::base是一個靜態參考。在這裏,您intialize它:

Base& Base::base=Base::getBaseInstance(); 

從這時開始(即使用base執行代碼之前),base指基實例(即在Base::getBaseInstance()聲明的靜態實例)。

然後,當您完成作業後,將不再更改參考,但是您會將對象複製到由base(其類型爲base,因此爲切片!)引用的對象中。

解決方法可能是使base :: base指針。通過這種方式,您可以將其更改並指向派生對象。然而,這是否符合我們的單例方法(因爲那樣你就會有基礎對象和派生對象)。

+0

重新「因此切片」,沒有數據成員,因此不可能檢測到切片。 –

+0

謝謝隊友,我知道指針方法。只要避免它具有最少數量的跡線(英特爾跡線/預解碼)。再次感謝。 –

+0

@ Cheersandhth.-Alf可能沒有數據成員,但有虛擬功能。由於作業是關於普通對象的,Derived類型會丟失,所以它不再使用預期的虛擬函數。我不是natike英語人士:當有些信息丟失時,我使用「切片」[使用此定義](http://stackoverflow.com/questions/274626/what-is-object-slicing),但可能是你可以提出一個更好的措辭。 – Christophe

相關問題