2013-06-12 63 views
20

說我有一個需要幾個常量才能運行的類。幾個成員函數需要使用這些常量。 #define的使用令人不悅,因爲它可能導致衝突。常量是8位或16位的十六進制模式,並存儲爲uint8_t或uint16_t。這些常量也不會因類的實例而改變,因此只有一個常量副本可以節省內存(雖然內存很少)。C++靜態常量成員變量用法

有什麼不當,或者是實現上述,而不是簡單地做類似如下的更好的辦法:

// mycode.h 
// ....... 
class myclass { 
private: 
    static const uint16_t kMyClassConstant_ = 0xBEEF; 
// ....... 
}; 

在此先感謝您的幫助。

+0

不,這沒什麼錯。 (希望有些C++專家不需要糾正我:)) – xxbbcc

+0

你可能會在http://codereview.stackexchange.com得到更好的答案。 –

+2

是的,這是一種聲明全局常量的常用方法。 –

回答

38

鑑於你對情況的描述,我會說使用static const成員是一個好方法。在C++ 11中,您可能希望將其更改爲static constexpr以強調它是一個編譯時常量,但不會因此而有效改變。

如果您在代碼中的某處以與one-definition-rule(odr)相關的方式引用myclass::kMyClassContant_,在需要引用(包括const引用)的上下文中,編譯器會抱怨沒有常量的定義。在這種情況下,僅僅在課堂上聲明和初始化它是不夠的。這可能會迫使你單獨的聲明和定義:

// mycode.h 
class myclass { 
private: 
    static const uint16_t kMyClassConstant_; 
}; 

// mycode.cpp 
const uint16_t myclass::kMyClassConstant_ = 0xBEEF; 

爲了避免維護單獨的聲明和定義的麻煩,有些人喜歡聲明,而不是實際的變量內聯constexpr功能:

// mycode.h 
class myclass { 
private: 
    static constexpr uint16_t kMyClassConstant_() 
    { return 0xBEEF; } 
}; 

這對於許多與odr有關的問題是一個正確的解決方法,並且不會導致任何性能損失。它是否真的有用取決於維護一個普通靜態常量的單獨聲明和定義的負擔是多少。如果你期望你的常量永遠不會隨着你的代碼的發展而改變,那麼使用具有單獨定義的普通靜態常量是可取的。但是,如果您頻繁修改常量的定義,不得不重新編譯定義文件並將其重新鏈接到項目的所有相關部分,可能會使您認爲上述基於功能的解決方案是更好的選擇。

對數據類型的最終評論:使用std::uint16_t將其強制爲16位可能會很有用,如果您需要以緊湊形式存儲大量這些值。否則,實際大小可能無關緊要,在這種情況下,std::uint_fast16_t(可能大於16位)可能會更好。

+7

我一直在關注你的答案,並且據我所知,他們在澄清和精確度方面是最好的。這與一些具有很高「聲譽」的人形成了對比,他們不斷迴應神祕感而不是回答問題。恭喜(+1) – Ayrosa

+1

@ 411165感謝您的好評:)感謝您在學習我(和其他人)SO帖子的過程中的徹底性! – jogojapan

+0

這個答案非常有用,但我沒有得到關於重新編譯的推理。我認爲使用內聯成員函數(在類定義中,因此在頭文件中),對值的每次更改都需要對所有客戶端翻譯單元(包括該頭文件)進行_recompilation_,儘管它們不能直接訪問那些私有成員函數。另一方面,使用單獨的聲明和定義,更改值只會更改實現模塊,需要重新編譯一次,並且只需要_relinking_個客戶端。這少了,不多。 –

5

你可以使用類型的特徵來實現這一點:

#include <type_traits> 

class myclass { 
private: 
    typedef std::integral_constant<uint16_t , 0xBEEF> kMyClassConstant; 

    // ... 
}; 

用作myclass::kMyClassConstant::value

這顯示了實現積分常量的目的,並防止您意外地獲取常量的地址。