2014-09-04 77 views
9

在C++ 11中,如果基類定義了自己的移動(複製)構造函數(賦值運算符),其子類是否需要定義自己的移動(複製)構造函數(賦值運算符)在哪裏調用基類的相應構造函數/運算符顯式調用?在子類中默認移動構造函數

每次都清楚地定義構造函數,析構函數,移動/複製構造函數(賦值運算符)是一個好主意嗎?

struct Base { 
    Base() {} 
    Base(Base&& o); 
}; 

struct Sub : public Base { 
    Sub(Sub&& o) ; // Need I do it explicitly ? If not,what the compiler will do for me 
}; 
+0

編譯器將生成一個默認的移動構造函數,如果你沒有任何的,但並非總是如此(例如參見(http://en.cppreference.com/w/ [對於不是創建時的列表,這個參考] CPP /語言/ move_constructor))。但是,您不能依賴默認移動(或任何其他)構造函數來「做正確的事情」,特別是您不能依賴基類移動構造函數,因爲它不知道任何子類。還請閱讀[三(或自C++ 11以來的五年)規則](https://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29)。 – 2014-09-04 11:52:43

+0

@Joachim:你在吸菸?三規則被「零規則」取代,而不是「五規則」。絕大多數類的默認複製/移動構造函數應該足夠了。 – Puppy 2014-09-04 11:57:17

+1

@Puppy我會說三條規則和零規則相互補充,而不是一個排除或取代另一個。僅僅因爲你可以遵循一些類的零規則,並不意味着你可以(或者應該)爲所有類而做。 – 2014-09-04 12:10:04

回答

4

編譯器將生成一個默認的移動構造函數,如果你不指定一個基類(除some cases,例如有一個基類刪除移動構造函數),但你應該在任何情況下,通話明確基類的一個,如果你有它:

Sub(Sub&& o) : Base(std::move(o)) 
+2

這是完美的嗎? Sub &&是一個右值引用,所以它只會作爲右值被轉發。如果你使用通用引用和'std :: forward',那將是完美的轉發。 – 0x499602D2 2014-09-04 12:08:44

+0

@ 0x499602D2沒有完美轉發OP的代碼會生成一個錯誤,因爲複製構造函數在Base中被隱式刪除,我是否錯過了某些東西? – 2014-09-04 12:11:53

+1

對不起,我明白了你的觀點:只有rvalues可以通過那裏。我同意,並不真正涉及完美轉發的意義上的術語。一個std :: move在這裏就足夠了 – 2014-09-04 12:14:33

1

根據標準(N379712.8/9複製和移動對象類[class.copy]:

如果class X的定義不明確宣佈此舉的構造函數,一個將被隱爲缺省的聲明,當且僅當

- X沒有一個用戶聲明的拷貝構造函數,

- X沒有一個用戶聲明的拷貝賦值運算符,

- X沒有一個用戶聲明的舉動賦值運算符,以及

- X沒有一個用戶聲明的析構函數。

因此,如果您的class符合上述要求,那麼默認的移動構造函數將爲您隱式聲明。

如前所述,基類不知道任何子類。因此,無論您在一個基類中聲明移動構造函數,都不會影響其子類中移動構造函數的隱式生成。

只要它涉及你是否應該明確聲明一個類的構造函數/析構函數等,這裏有很好的article

0

不,你沒有。我會像默認/複製構造函數一樣自動生成。


this page

隱式聲明移動構造函數

如果提供了一類式(結構,類或聯合)沒有用戶定義移動的構造,和以下全部爲真:

there are no user-declared copy constructors 
there are no user-declared copy assignment operators 
there are no user-declared move assignment operators 
there are no user-declared destructors 
(until C++14) the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section 

那麼編譯器將聲明一個移動構造函數作爲其類的內聯公共成員,並帶有簽名T :: T(T & &)。

一個類可以有多個移動構造函數,例如,兩個T :: T(const的Ť& &)和T :: T(Ť& &)。如果存在某些用戶定義的移動構造函數,則用戶仍可以強制生成隱式聲明的移動構造函數,並使用關鍵字default。

您的struct Sub沒有用戶聲明的複製構造函數,複製賦值運算符,移動賦值運算符或析構函數。

而且,

瑣碎移動構造函數

類T的此舉構造是平凡的,如果滿足以下所有的條件爲真:

It is not user-provided (meaning, it is implicitly-defined or defaulted), and if it is defaulted, its signature is the same as implicitly-defined 
T has no virtual member functions 
T has no virtual base classes 
The move constructor selected for every direct base of T is trivial 
The move constructor selected for every non-static class type (or array of class type) member of T is trivial 

T has no non-static data members of volatile-qualified type 

(因爲C++ 14 )

甲瑣碎移動構造函數是執行一個構造與平凡複製構造函數相同的動作,也就是通過std :: memmove生成對象表示的副本。所有與C語言(POD類型)兼容的數據類型都可以移動。

隱式定義的移動構造函數

如果隱式地聲明的移動構造函數既不是刪除也不瑣碎,定義由編譯器(即,產生和編譯的函數體)。對於聯合類型,隱式定義的移動構造函數複製對象表示(如std :: memmove)。 對於非聯合類類型(類和結構體),移動構造函數使用xvalue參數進行直接初始化,以初始化順序執行對象基和非靜態成員的完全成員移動。

移動構造函數Base不是微不足道的(它是用戶定義的)。所以,Sub的隱式定義的移動構造函數將作爲「移動的構造函數執行對象的基地和非靜態成員的全成員明智之舉,在他們的初始化順序,使用直接初始化與x值的說法。」