2012-12-28 44 views
3

首先,讓我的對面看看這兩個代碼段我已經準備了關注:在類中靜態方法VS類中的本地方法

struct Quaternion 
{ 
public: 

    float X, Y, Z, W; 

    Quaternion(float x, float y, float z, float w) 
     : 
     X(x), Y(y), Z(z), W(w) 
    {} 

    void Normalise() 
    { 
     float num = (((this->X * this->X) + (this->Y * this->Y)) + 
      (this->Z * this->Z)) + (this->W * this->W); 
     float num2 = 1.0f/(static_cast<float>(std::sqrt(static_cast<double>(num)))); 
     this->X *= num2; 
     this->Y *= num2; 
     this->Z *= num2; 
     this->W *= num2; 
    } 

    void Conjugate() 
    { 
     this->X = -this->X; 
     this->Y = -this->Y; 
     this->Z = -this->Z; 
    } 
}; 

以上是「本地方法」,我在標題中提到.. 現在我們來看看我在課堂上'靜態方法'的含義。

struct Quaternion 
{ 
public: 

    float X, Y, Z, W; 

    Quaternion(float x, float y, float z, float w) 
     : 
     X(x), Y(y), Z(z), W(w) 
    {} 

    static Quaternion& Normalise(Quaternion& quat) 
    { 
     float num = (((quat.X * quat.X) + (quat.Y * quat.Y)) + 
      (quat.Z * quat.Z)) + (quat.W * quat.W); 
     float num2 = 1.0f/(static_cast<float>(std::sqrt(static_cast<double>(num)))); 
     // Assuming operator= overloaded.. 
     quat = Quaternion(quat.X * num2, quat.Y * num2, quat.Z * num2, quat.W * num2); 
     return quat; 
    } 

    static Quaternion& Conjugate(Quaternion& quat) 
    { 
     // Assuming operator= overloaded.. 
     quat = Quaternion(-quat.X, -quat.Y, -quat.Z, quat.W); 
     return quat; 
    } 
}; 

我的問題是......什麼是折衷?效果如何?使用這些靜態類方法而不是本地方法。兩者都有類似的用法:

編輯:忽略* .ToString功能,它是psuedocode - 我相信你可以想象它會做什麼;因此它的實現是多餘的,因爲它只是輸出原始的X,Y,Z,W值。

的 '本地方法' 類的用法:

int main() 
{ 
    Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f); 

    std::cout << testQuat.ToString(); // (6, 6, 6, 1.3) 

    testQuat.Conjugate(); 

    std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3) 

    return 0; 
} 

現在的「靜態方法類的用法:

int main() 
{ 
    Quaternion testQuat(6.0f, 6.0f, 6.0f, 1.3f); 

    std::cout << testQuat.ToString(); // (6, 6, 6, 1.3) 

    testQuat = Quaternion::Conjugate(testQuat); 

    std::cout << testQuat.ToString(); // (-6, -6, -6, 1.3) 

    return 0; 
} 

那麼有什麼區別?這些是靜態方法而不是對象。哪個更好?這只是設計選擇的問題嗎?

回答

3

他們是兩個完全不同的東西。其中一個修改對象a OOP,另一個返回不同的對象a功能樣式。如果這是我的選擇,我會保留它們兩個,因爲它們都有用例。而作爲免費功能基礎上,成員函數,即我將實現功能性風格:

Quaternion normalize(Quaternion quat) 
{ 
    quat.normalize(); 
    return quat; 
} 

[我明確地考慮通過此值quat,給出了副本,省音機會]

請注意,您的靜態實現是錯誤的,他們正在返回一個臨時引用。這是未定義的行爲,你應該從你的編譯器得到一個警告,並且如果你足夠幸運的話還有一個運行時崩潰。

1

首先,你的第二種方法不應該編譯,儘管我認爲MSVC++有一個允許臨時對象綁定到非const引用的錯誤。即使添加const&也不會使功能更好:它們仍然不起作用,因爲調用者獲得了臨時引用。這麼多的實施。

關於界面設計,我認爲真正的權衡不在static成員之間(如果你願意的話,你可以額外增加它們),但是不帶參數的函數應該改變對象本身還是應該返回相應修改的對象:

// return a copy: 
Quaternion Quaternion::conjugate() const { 
    return Quaternion(-this->X, -this->Y, -this->Z, this->W); 
} 

// modify the object itself: 
void Quaternion::conjugate() { 
    this->X = -this->X; 
    this->Y = -this->Y; 
    this->Z = -this->Z; 
} 

雖然這兩個超載實際上可以住在同一個班級我會提供他們兩個!哪一個更適合哪個接口是一種選擇。我個人更喜歡後者,可能創建一個static成員變異對象本身:

/* static */ void Quaternion::conjugate(Quaternion& object) { 
    object = object.conjugate(); 
} 
0

除了對於這兩種方法之間的差異的其他答案,靜態方法難以嘲笑/存根,如果你想聘請單元測試。

例如,假設您有一個名爲ClassThatUsesQuaternion的類使用Quaternion。如果Quaternion有很多靜態方法,你將總是有真實的數據。另一方面,如果您將四元數方法轉換爲虛擬方法,您將能夠重新定義所有方法,在您的控制下創建一個環境測試。你甚至可以添加一個模擬框架,如gmock來表達你的期望。