簡體   English   中英

我可以將final關鍵字應用於C ++ 11中的POD(標准布局)結構嗎?我是不是該?

[英]Can I apply the final keyword to a POD (standard-layout) struct in C++11 ? Should I?

在一個充滿對象(具有適當行為)和相對較少的非面向對象結構(僅由數據字段和無方法組成)的C ++項目中,我想防止意外濫用這些結構,其中一個可能會嘗試創建一個繼承自它的類。

根據我的理解,因為這些“POD”(普通舊數據)結構沒有虛擬析構函數,所以無法通過POD類型的指針正確刪除派生類對象(如果允許創建它) 。

這似乎是C ++ 11“final”關鍵字的一個很好的用例,它將類或結構標記為不可繼承。

但是,我想知道“final”關鍵字是否會導致結構變為非POD?

我懷疑標准文檔可能已經解決了這個問題,但我沒有足夠的智慧來篩選很長的文檔來查找。 任何有用的指針都是受歡迎的。

注意:我只是不知道它通過了一些編譯器供應商的編譯。 通過匯編不保證:

  • 編譯的代碼是否會在所有情況下正確執行(特別是當技術應用於更大,更復雜的項目時),
  • C ++標准組織是否打算以這種方式使用它。
#include <iostream>
using namespace std;

struct Pod final
{
    int a;
    int b;
    int c;
};

#if 0
class FailsBecauseCannotDeriveFromFinalAnything : public Pod
{
};
#endif

class ContainsSomethingFinalAsMember
{
public:
    ContainsSomethingFinalAsMember() : pod() {}
private:
    Pod pod;
};

int main() 
{
    std::cout << std::is_pod < Pod > :: value << std::endl;
    return 0;
}

根據我的理解,因為這些“POD”(普通舊數據)結構沒有虛擬析構函數,所以無法通過POD類型的指針正確刪除派生類對象(如果允許創建它) 。

給定一個原始指針是不可能的,但是可以給出一個智能指針對象,例如std::shared_ptr或帶有適當刪除器的std::unique_ptr

由於智能指針是標准化的,因此沒有理由繼續遵循手動使用delete操作符的不良做法。 當然,不應該圍繞與delete運算符的兼容性來設計類。 每個類接口的設計都應考慮其特定用途。

不,讓每個課程都是final或多態的並不是一個好習慣。

但是,我想知道“final”關鍵字是否會導致結構變為非POD?

不,它仍然是POD。 POD的要求是標准布局(反過來不需要基類,成員之間沒有訪問說明符,沒有虛擬任何東西)和普通的特殊成員函數(復制/移動構造函數,賦值運算符,析構函數)。

但是,POD-ness的目的是允許你使用memcpy而不是正確構造對象,這是好的C ++代碼可以避免的。

標記類final並不會改變其POD狀態。 引用C ++ 11:

9 [班級]:

6一個簡單的可復制類是一個類:

  • 沒有非平凡的拷貝構造函數(12.8),
  • 沒有非平凡的移動構造函數(12.8),
  • 沒有非平凡的副本賦值運算符(13.5.3,12.8),
  • 沒有非平凡的移動賦值運算符(13.5.3,12.8),和
  • 有一個簡單的析構函數(12.4)。

一個普通的類是一個具有普通默認構造函數(12.1)並且可以輕易復制的類。 [ 注意:特別是,一個簡單的可復制或普通的類沒有虛函數或虛基類。 - 尾注 ]

7 標准布局類是一個類:

  • 沒有非標准布局類(或此類類型的數組)或引用類型的非靜態數據成員,
  • 沒有虛函數(10.3),也沒有虛基類(10.1),
  • 對所有非靜態數據成員具有相同的訪問控制(第11條),
  • 沒有非標准布局基類,
  • 或者在最派生類中沒有非靜態數據成員,並且最多只有一個具有非靜態數據成員的基類,或者沒有具有非靜態數據成員的基類,並且
  • 沒有與第一個非靜態數據成員相同類型的基類。

標准布局結構是使用類鍵 struct類鍵 class定義的標准布局class ...

10 POD結構是一個非聯合類,它既是普通類,也是標准布局類,並且沒有非POD結構類型的非靜態數據成員,非POD聯合(或此類型的數組)。 ...

12.1 [class.ctor]

5 ...如果默認構造函數不是用戶提供的,則默認構造函數是微不足道的,如果:

  • 它的類沒有虛函數(10.3),也沒有虛基類(10.1),和
  • 沒有類的非靜態數據成員有一個大括號或等於初始化器,和
  • 它的所有直接基類都有簡單的默認構造函數,和
  • 對於類類的所有非靜態數據成員(或其數組),每個這樣的類都有一個普通的默認構造函數。

否則,默認構造函數是非平凡的。

12.4 [class.dtor]

5 ...如果不是用戶提供的,析構函數是微不足道的,如果:

  • 析構函數不是虛擬的,
  • 它的所有直接基類都有瑣碎的析構函數
  • 對於類類的所有非靜態數據成員(或其數組),每個這樣的類都有一個簡單的析構函數。

否則,析構函數是非平凡的。

12.8 [class.copy]

12,用於A類復制/移動的構造X是微不足道的,如果它不是用戶提供的,並且如果-類X沒有虛函數(10.3),並且沒有虛基類(10.1),以及-選擇要復制的構造/移動每個直接基類子對象是微不足道的,並且 - 對於類類型(或其數組)的X每個非靜態數據成員,選擇復制/移動該成員的構造函數是微不足道的;

否則復制/移動構造函數是非平凡的。

25如果不是用戶提供的,則X類的復制/移動賦值運算符是微不足道的

  • class X沒有虛函數(10.3),沒有虛基類(10.1),和
  • 選擇復制/移動每個直接基類子對象的賦值運算符是微不足道的,並且
  • 對於類型(或其數組)的X每個非靜態數據成員,選擇復制/移動該成員的賦值運算符是微不足道的;

否則復制/移動賦值運算符是非常重要的。

如您所見,POD結構的定義沒有考慮該類是否具有class-virt-specifier final

暫無
暫無

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

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