[c++] 你如何在C ++中創建一個靜態類?



5 Answers

考慮Matt Price的解決方案

  1. 在C ++中,“靜態類”沒有意義。 最近的事情是只有靜態方法和成員的類。
  2. 使用靜態方法只會限制你。

你想要的是,用C ++語義表達,把你的函數(因為它一個函數)放在名字空間中。

編輯2011-11-11

C ++中沒有“靜態類”。 最接近的概念是只有靜態方法的類。 例如:

// header
class MyClass
{
   public :
      static void myMethod() ;
} ;

// source
void MyClass::myMethod()
{
   // etc.
}

但是你必須記住,“靜態類”是Java類語言(例如C#)中的黑客,它們無法擁有非成員函數,所以它們不得不將它們作為靜態方法在類中移動。

在C ++中,你真正想要的是一個非成員函數,你將在一個名字空間中聲明:

// header
namespace MyNamespace
{
   static void myMethod() ;
}

// source
namespace MyNamespace
{
   void myMethod()
   {
      // etc.
   }
}

這是為什麼?

在C ++中,名稱空間比“Java靜態方法”模式的類更強大,因為:

  • 靜態方法可以訪問類私有符號
  • 私有靜態方法仍然可見(如果不可訪問)給每個人,這會破壞封裝
  • 靜態方法不能被提前聲明
  • 靜態方法不能被類用戶重載而不修改庫頭
  • 沒有任何東西可以通過靜態方法來完成,它不可能比同一個命名空間中的一個(可能是朋友)非成員函數做得更好
  • 命名空間有它們自己的語義(它們可以組合,可以是匿名的等)
  • 等等

結論:不要在C ++中復制/粘貼Java / C#的模式。 在Java / C#中,該模式是強制性的。 但在C ++中,這是糟糕的風格。

編輯2010-06-10

有人讚成靜態方法,因為有時需要使用靜態私有成員變量。

我有點不同意,如下所示:

“靜態私人會員”解決方案

// HPP

class Foo
{
   public :
      void barA() ;
   private :
      void barB() ;
      static std::string myGlobal ;
} ;

首先,myGlobal被稱為myGlobal,因為它仍然是一個全局私有變量。 看看CPP的來源將闡明:

// CPP
std::string Foo::myGlobal ; // You MUST declare it in a CPP

void Foo::barA()
{
   // I can access Foo::myGlobal
}

void Foo::barB()
{
   // I can access Foo::myGlobal, too
}

void barC()
{
   // I CAN'T access Foo::myGlobal !!!
}

乍看之下,自由功能barC無法訪問Foo :: myGlobal的事實從封裝的角度來看似乎是一件好事......這很酷,因為看著HPP的人不能訪問(除非訴諸破壞)訪問富:: myGlobal。

但是如果仔細觀察它,你會發現這是一個巨大的錯誤:不僅你的私有變量必須在HPP中聲明(並且對全世界都是可見的,儘管它是私有的),但是你必須聲明在相同的HPP所有(如在ALL)功能,將被授權訪問它!

因此, 使用私人靜態會員就像走在裸體的外面,讓愛人在你的皮膚上紋身:沒有人有權觸摸,但每個人都可以偷看。 獎金:每個人都可以擁有被授權與你的貴賓玩的人的姓名。

private確實...... :-D

“匿名命名空間”解決方案

匿名命名空間將有利於將事物私有化。

首先,HPP標題

// HPP

namespace Foo
{
   void barA() ;
}

只是為了確定你的評論:barB和myGlobal沒有無用的聲明。 這意味著沒有人閱讀頭文件知道barA背後隱藏著什麼。

然後,CPP:

// CPP
namespace Foo
{
   namespace
   {
      std::string myGlobal ;

      void Foo::barB()
      {
         // I can access Foo::myGlobal
      }
   }

   void barA()
   {
      // I can access myGlobal, too
   }
}

void barC()
{
   // I STILL CAN'T access myGlobal !!!
}

正如你所看到的,就像所謂的“靜態類”聲明一樣,fooA和fooB仍然能夠訪問myGlobal。 但沒有其他人可以。 除此之外,沒有其他人知道fooB和myGlobal甚至存在!

與在她裸體上行走的“靜態類”不同,她的地址簿上紋著她的皮膚,“匿名”命名空間完全穿著 ,這看起來好像封裝了AFAIK。

真的有關係嗎?

除非你的代碼的用戶是破壞者(我會讓你作為一個練習,發現如何用一個骯髒的行為 - 未定義的黑客攻擊來訪問公共類的私有部分......), private是什麼如果它在頭中聲明的類的private部分中可見。

儘管如此,如果您需要添加另一個可以訪問私有成員的“私有函數”,您仍然必須通過修改頭部來向全世界聲明它,但就我而言,這是一個悖論: 如果我更改了實現我的代碼(CPP部分),那麼界面(HPP部分)不應該改變。 引用列奧尼達斯:“ 這是封裝!

編輯2014-09-20

何時類靜態方法實際上比具有非成員函數的名稱空間更好?

當您需要將功能分組在一起並將該組提供給模板時:

namespace alpha
{
   void foo() ;
   void bar() ;
}

struct Beta
{
   static void foo() ;
   static void bar() ;
};

template <typename T>
struct Gamma
{
   void foobar()
   {
      T::foo() ;
      T::bar() ;
   }
};

Gamma<alpha> ga ; // compilation error
Gamma<Beta> gb ;  // ok
gb.foobar() ;     // ok !!!

因為,如果一個類可以是一個模板參數,那麼命名空間就不能。

Question

你如何在C ++中創建一個靜態類? 我應該能夠做到這樣的事情:

cout << "bit 5 is " << BitParser::getBitAt(buffer, 5) << endl;

假設我創建了BitParser類。 BitParser類定義是什麼樣的?




命名空間對於實現“靜態類”可能不那麼有用的一種情況是使用這些類來實現繼承的組合。 命名空間不能成為類的朋友,因此不能訪問類的私有成員。

class Class {
 public:
  void foo() { Static::bar(*this); }    

 private:
  int member{0};
  friend class Static;
};    

class Static {
 public:
  template <typename T>
  static void bar(T& t) {
    t.member = 1;
  }
};



與其他託管編程語言不同,“靜態類”在C ++中沒有意義。 你可以使用靜態成員函數。




如果您正在尋找一種將“靜態”關鍵字應用於類的方法,例如您可以在C#中使用該方法

靜態類只是編譯器手持你並阻止你寫任何實例方法/變量。

如果你只寫了一個沒有任何實例方法/變量的普通類,它是一樣的,這就是你在C ++中所做的事情




我可以寫static class嗎?

,根據C ++ 11 N3337標準草案附錄C 7.1.1:

更改:在C ++中,靜態或外部說明符只能應用於對像或函數的名稱。 在C ++中將這些說明符與類型聲明一起使用是非法的。 在C中,這些說明符在類型聲明中使用時被忽略。 例:

static struct S {    // valid C, invalid in C++
  int i;
};

基本原理:存儲類說明符在與類型關聯時沒有任何含義。 在C ++中,可以使用靜態存儲類說明符聲明類成員。 在類型聲明中允許使用存儲類說明符可能會使代碼對用戶造成混淆。

struct一樣, class也是一個類型聲明。

通過走附件A中的語法樹也可以得出同樣的結論。

有趣的是, static struct在C中是合法的,但沒有效果: 為什麼以及何時在C編程中使用靜態結構?




在託管C ++中,靜態類語法是: -

public ref class BitParser abstract sealed
{
    public:
        static bool GetBitAt(...)
        {
            ...
        }
}

... 遲到總比不到好...




Related