2011-02-12 239 views
2

所以我最近發現它使用了特別的技術我從來沒有見過的一些源代碼(成語);簡而言之;而不是爲有問題的類使用靜態變量,它使用類源文件中的局部變量。隱藏「靜態」類變量

myclass.h

class myclass { 
    //static int myint; 

public: 
    myclass(); 
    ~myclass(); 
    int count(); 
}; 

myclass.cpp

#include "myclass.h" 

int myint = 0; 

myclass::myclass() { 
    myint++; 
} 
myclass::~myclass() { 
    myint--; 
} 

int myclass::count() { 
    return myint; 
} 

的main.cpp

#include "myclass.h" 
#include <iostream> 

int main() { 
    myclass aclass; 
    myclass theclass; 

    std::cout << theclass.count(); //outputs 2 
    return 0; 
} 

我的問題是,爲什麼會有人採取這種方法比使用一個靜態變量?

我的看法是,由於變量只能被myclass類(private static)知道,並且繼承並不重要(在這種情況下),這可能會阻止其他人知道這個變量。但那是我能看到的唯一優勢;不知道這是否值得。

同樣的問題也適用於(靜止/非 - 靜態)是私有成員函數;當繼承不重要時。

編輯:閱讀後左右,我打算做一個刺,這是因爲有些人還在用C編程風格...

回答

7

這其實並不重要,你是否使用靜態成員變量或一個全局變量或一個本地聲明的靜態變量;唯一重要的是對象必須具有靜態存儲持續時間。除此之外,選擇主要基於個人偏好或編碼風格指南。

不幸的是,這段代碼基本上是沒錯的。雖然myint是「隱藏的」,只能從myclass.cpp中直接訪問,但它仍然具有外部鏈接。這意味着它可以訪問其他的翻譯單元(通過使用這些其他的翻譯單元extern int myint)和它的定義可以與其他翻譯單位的myint其它定義衝突。

爲了糾正這一點,應該要麼被聲明static(給它的內部連接),或者優選地,它應該在不具名命名空間聲明,

namespace { 
    int myint; 
} 

(一個在未命名的命名空間對象可能仍然有外部鏈接,但它是唯一命名的,所以它不能在編譯它的轉換單元外使用它的名稱。)

+0

+1使用無名命名空間,作爲[靜態]的[高級替代](http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static)。 – Nawaz 2011-02-12 08:48:03

+3

值得一提的是,大多數在線C++教程在技術上不正確,或者提倡窮人的風格。 (真的很傷心,真的......) – 2011-02-12 08:50:58

3

在您的示例中,該變量不是靜態的,並且在編譯單元外部在技術上是可見的if正確申報。如果這不是有意的,那麼如果另一個編譯單元對具有相同名稱的變量使用相同的技巧(要解決此問題,請參閱James McNellis的答案),可能會產生問題。

假設一個正常聲明爲靜態(例如,使用所述具名命名空間的方法)這種技術可以比類的靜態更好,因爲它完全隱藏從用戶類的變量。這意味着如果您需要添加或修改該變量,客戶端甚至不需要重新編譯(您只需重新編譯實現.cpp文件,然後重新連接程序)。如果您的類在大型項目的任何地方都可以使用,那麼這會有很大的不同(因爲內部細節的變化,只編譯一個文件而不是重新編譯整個世界)。

另外,如果靜態變量不是int而是更復雜的東西(例如模板類實例),那麼將該變量放在類中作爲靜態需要向客戶端公開更多的數據,引入不需要的依賴關係。

有時,這種不需要的依賴性問題被認爲非常重要,您可以找到「compiler firewall」成語的實現。這種隱藏是它的一個部分和簡單的版本。

1

我的問題是,爲什麼有人會採用這種方法使用靜態變量?

它是有道理的,如果你有東西隱藏 - 一個int不值得通常隱藏,但一個大型圖書館是。在某些情況下,作者可能也傾向於隱藏客戶的實現細節。

關於靜態函數 - 我通常會隱藏它們,如果它們只是免費的幫助器,並且實際上不屬於或者被要求成爲類接口的一部分。

一般來說,我只是爲了組織目的將它放在類接口中。