[英]'Helper' functions in C++
在重構一些舊代碼時,我已經刪除了一些實際上應該是靜態的公共方法,因為它們a)不對任何成員數據進行操作或調用任何其他成員函數和b)因為它們可能在其他地方證明是有用的。
這讓我想到了將“幫助”功能組合在一起的最佳方法。 Java / C#方式是將一類靜態函數與私有構造函數一起使用,例如:
class Helper
{
private:
Helper() { }
public:
static int HelperFunc1();
static int HelperFunc2();
};
但是,作為C ++,您還可以使用命名空間:
namespace Helper
{
int HelperFunc1();
int HelperFunc2();
}
在大多數情況下,我認為我更喜歡命名空間方法,但我想知道每種方法的優缺點。 例如,如果使用類方法,是否會有任何開銷?
開銷不是問題,命名空間雖然有一些優點
您可以使用命名空間別名來優勢(調試/發布,特定於平台的幫助程序,......)
我做過類似的事情
namespace LittleEndianHelper { void Function(); } namespace BigEndianHelper { void Function(); } #if powerpc namespace Helper = BigEndianHelper; #elif intel namespace Helper = LittleEndianHelper; #endif
可以在namespace
使用class
(或struct
)的情況是當需要類型時,例如:
struct C {
static int f() { return 33; }
};
namespace N {
int f() { return 9; }
}
template<typename T>
int foo() {
return T::f();
}
int main() {
int ret = foo<C>();
//ret += foo<N>(); // compile error: N is a namespace
return ret;
}
為了增加Pieter的出色響應,命名空間的另一個優點是你可以轉發聲明你放在其他地方的命名空間中的東西,尤其是結構...
//Header a.h
// Lots of big header files, spreading throughout your code
class foo
{
struct bar {/* ... */);
};
//header b.h
#include a.h // Required, no way around it, pulls in big headers
class b
{
//...
DoSomething(foo::bar);
};
並使用命名空間......
//Header a.h
// Big header files
namespace foo
{
struct bar {/* ... */);
}
//header b.h
// Avoid include, instead forward declare
// (can put forward declares in a _fwd.h file)
namespace foo
{
struct bar;
}
class b
{
//...
// note that foo:bar must be passed by reference or pointer
void DoSomething(const foo::bar & o);
};
一旦你最終得到一個跨越數百個源文件的項目,轉發聲明會在小標題更改后對編譯時間產生很大影響。
由於枚舉錯誤,答案太好了,不能讓它死掉(見評論)。 我用結構替換了枚舉(只能在C ++ 0x中進行前向聲明,而不是在今天的C ++中)。
使用命名空間的主要優點是你可以重新打開它並在以后添加更多東西,你不能用類來做。 這使得這種方法更適合松散耦合的助手(例如,您可以為整個庫創建一個Helpers名稱空間,就像所有STL在:: std中一樣)
類的主要優點是可以使用它將它嵌套在類中,不能在類中嵌套命名空間。 這使得這種方法更適合緊密耦合的助手。
在類和命名空間中,它們不會有任何額外的開銷。
復制/修剪/重寫我的答案部分如何正確使用C ++中的命名空間? 。
您可以使用“使用”來避免重復輔助函數的“前綴”。 例如:
struct AAA
{
void makeSomething() ;
} ;
namespace BBB
{
void makeSomethingElse() ;
}
void willCompile()
{
AAA::makeSomething() ;
BBB::makeSomethingElse() ;
}
void willCompileAgain()
{
using BBB ;
makeSomethingElse() ; // This will call BBB::makeSomethingElse()
}
void WONT_COMPILE()
{
using AAA ; // ERROR : Won't compile
makeSomething() ; // ERROR : Won't compile
}
命名空間不僅僅是包。 另一個例子可以在Bjarne Stroustrup的“The C ++ Programming Language”中找到。
在8.2.8命名空間組合的“特別版”中,他描述了如何將兩個名稱空間AAA和BBB合並到另一個名為CCC的名稱空間中。 因此,CCC成為AAA和BBB的別名:
namespace AAA
{
void doSomething() ;
}
namespace BBB
{
void doSomethingElse() ;
}
namespace CCC
{
using namespace AAA ;
using namespace BBB ;
}
void doSomethingAgain()
{
CCC::doSomething() ;
CCC::doSomethingElse() ;
}
您甚至可以從不同的命名空間導入選擇符號,以構建您自己的自定義命名空間界面。 我還沒有找到它的實際用途,但從理論上講,它很酷。
命名空間提供了Koenig查找的額外優勢。 使用幫助程序類可能會使您的代碼更加冗長 - 您通常需要在調用中包含幫助程序類名稱。
命名空間的另一個好處是可讀性。 對於類,您需要包含“Helper”之類的單詞,以便稍后提醒您特定類不用於創建對象
在實踐中,兩者都沒有開銷。 編譯后,只使用名稱修改不同。
在創建輔助函數時,我傾向於使用匿名命名空間。 因為它們(通常)只能由關心它們的模塊看到,所以它是控制依賴關系的好方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.