簡體   English   中英

C ++ 11中默認函數的重點是什么?

[英]What's the point in defaulting functions in C++11?

C ++ 11增加了告訴編譯器創建任何特殊成員函數 的默認實現的能力。 雖然我可以看到刪除函數的價值,但顯式默認函數的值是什么? 只需將其留空,編譯器無論如何都會這樣做。

我能看到的唯一一點是,只有當沒有其他構造函數存在時才會創建默認構造函數:

class eg {
public:
    eg(int i);
    eg() = default; 
};

但這真的比你現在這樣做好嗎?

class eg {
public:
    eg(int i);
    eg() {}
};

或者我錯過了一個用例?

默認構造函數將具有聲明,並且該聲明將受到正常訪問規則的約束。 例如,您可以使默認的復制構造函數受到保護。 如果沒有這些新聲明,默認生成的成員將是公共的。

來自Stroustrup網站的這些例子可能會幫助您理解這一點:

默認和刪除的功能 - 默認控制

現在可以直接表達“禁止復制”的常用習語:

 class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; }; 

相反,我們也可以明確地說我們想要默認的復制行為:

 class Y { // ... Y& operator=(const Y&) = default; // default copy semantics Y(const Y&) = default; }; 

明確關於默認值顯然是多余的,但是對這種效果的評論以及(更糟糕的)明確定義復制操作的用戶意味着給出默認行為並不罕見。 將它留給編譯器來實現默認行為更簡單,更不容易出錯,並且通常會導致更好的目標代碼。 “默認”機制可用於任何具有默認值的函數。 “刪除”機制可用於任何功能。 例如,我們可以消除不需要的轉換,如下所示:

 struct Z { // ... Z(long long); // can initialize with an long long Z(long) = delete; // but not anything less }; 

除了更改生成函數的可訪問性(私有/受保護)之外,您還可以將它們設置為虛擬。

struct S
{
    virtual ~S();
    virtual S& operator=(const S&);
};

S::~S() = default;
S& S::operator=(const S&) = default;

可以修改默認函數的以下方面:

  • 訪問(非公開)
  • 虛擬
  • 顯式(構造函數)
  • 例外規范
  • 參數的常數

但要這樣做,必須在課外定義函數( C ++ 0x最終委員會草案中的8.4.2 / 2)。

勞倫斯·克勞爾的原始提案版本就在這里

感謝Roger Pate的澄清和引用。

1)隱式生成的析構函數目前不是虛擬的。 所以你需要定義它們以使它們成為虛擬的,在這種情況下它們不那么有效。 使用= default,您將同時擁有virtual和efficent作為隱式生成的析構函數。

2)它們將具有訪問說明符,與隱式生成的說明符相反。

3)如果你內聯你的默認構造函數,你的課程仍然是微不足道的。

這篇文章詳細闡述了這一新功能。

參見Scott Meyer的偉大着作“ Effective Modern C ++ ”中的第17項。 它描述了生成(或生成)默認復制構造函數,復制操作和移動操作的許多條件。

換句話說,編譯器可能不“無論如何”。 但是,如果默認的特殊成員函數有意義,則用戶可以使用“default”關鍵字明確告訴編譯器生成一個默認函數,否則不會生成該函數。

從第17項末尾的事情開始:

  • 僅為缺少顯式聲明的移動操作,復制操作或析構函數的類生成移動操作。

  • 復制構造函數僅針對缺少顯式聲明的復制構造函數的類生成,如果聲明了移動操作,則會刪除它。 僅為缺少顯式聲明的復制賦值運算符的類生成復制賦值運算符,並且如果聲明了移動操作,則將其刪除。 不推薦使用顯式聲明的析構函數在類中生成復制操作。

我懷疑能夠默認生成復制構造函數實際上是有用的。 我無法看到默認生成默認構造函數的用法,因為正如您所說,您鍵入的實現將更短。

如果您有一個具有大量屬性的類,則默認對於復制構造函數更有用。 例如,如果您有這個類:

class MyClass {
private:
   int offset;
   std::string name;
   std::vector<Person*> relatives;
   float weight;
   MyClass* spouse;
   Vehicle* car;
   double houseArea;
   Date birth;
   Person* parents[2];

public:
   /* Default constructor will be defined here */
};

而不是這樣定義復制構造函數:

MyClass(const MyClass& that) :
   offset(that.offset),
   name(that.name),
   relatives(that.relatives),
   weight(that.weight),
   spouse(that.spouse),
   car(that.car),
   houseArea(that.houseArea),
   birth(that.birth),
   parents(that.parents)
{}

你會這樣定義:

MyClass(const MyClass&) = default;

對我來說,它的禁用功能很有用,對於我目前創建的大多數類,我禁用復制和賦值 - 如果有一個編譯器可以識別的功能,而不是依賴於鏈接器錯誤,那將是很好的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM