2016-12-09 54 views
3

我有以下類別:如何輕鬆公開C++類的所有私有成員我是朋友?

class Foo 
{ 
friend class FriendFoo; 
private: 
    int private_number1; 
    int private_number2; 
    int private_function1(); 
    int private_function2(); 
}; 

class FriendFoo 
{ 
public: 
    Foo& foo; 
    FriendFoo(Foo& foo_) : foo(foo_) 
    { 
    } 

    // I don't want to write the following adaptors: 
    int getPrivateNumber1() 
    { 
     return foo.private_number1; 
    } 

    int getPrivateNumber2() 
    { 
     return foo.private_number2; 
    } 

    int private_function1() 
    { 
     return foo.private_function1(); 
    } 

    int private_function2() 
    { 
     return foo.private_function2(); 
    } 
}; 

問題:

我想通過FriendFoo訪問的Foo所有的私有成員來自外部的,但我不想修改類FriendFoo每當私有成員的Foo更改(或另一個添加)。 理想情況下,我想擺脫所有適配器。有沒有辦法如何實現這一點?

背景:

我想用這個私有方法的單元測試,我選擇了做它的「朋友」的方式。 請不要在這裏討論/批評私人方法的測試,關於它的很多文章都是這樣寫的。 我只想找到解決具體的技術問題。

+0

如果您的所有函數都具有相同的簽名,您可以隨時將函數添加到私有向量;但我不明白你爲什麼不想改變friendFoo;您正在將測試對象的測試維護到測試對象,這是錯誤的地方。 – UKMonkey

+2

我很想創建[trust-issues]標籤。 – Quentin

+1

這是一個典型的問題,大多數單元測試框架允許測試私有函數解析代碼,儀器代碼和生成幫助者 – Garf365

回答

4

這裏有一個合法訪問private類的成員的方式,它也有優勢,代碼中沒有源代碼污染要測試。考慮

class Foo 
{ 
    int bar; 
}; 
在您的測試代碼

再建一個「穿甲彈」利用

template<typename Y, typename Y::type Member> 
struct Penetrator 
{ 
    friend typename Y::type get(Y){ 
     return Member; 
    } 
}; 

對於你想讀Foo每個成員,定義一個簡單的類

struct Foo_bar 
{ 
    typedef int Foo::*type; 
    friend type get(Foo_bar); 
}; 

和適當的專業化:

template struct Penetrator<Foo_bar, &Foo::bar>; 

然後,您可以編寫

int main() 
{ 
    Foo f; 
    f.*get(Foo_bar()) = 1; // write a value to it. 
} 
+0

@bolov:好點。爲了便於攜帶,您需要定義我現在添加的「簡單類」。上面應該「現成」編譯。 – Bathsheba

+0

恭喜。你設法讓我困惑〜5行模板,我傲慢地認爲在這一點上不可能發生。非常聰明的ideea。 +1 – bolov

+1

我沒有污染代碼的一點問題,添加一個朋友關鍵字對我來說可以。但是如果一個私人成員被添加到Foo中,現在我不得不添加一個適配器函數(並且我想擺脫這樣做)。但是,你建議創建一個結構和一個模板,這是更多的工作。恐怕這不是我的解決方案。 – bedrorom

0

我看你直接用朋友的方式訪問私有成員沒有任何適配器的唯一方法是,如果:

  • 有問題的類可以從
  • 導出
  • 您的單元測試框架允許您定義類別體內的個別測試用例(如方法)

這些restr對於你來說,可能是一種破壞交易的手段。

提出的解決方案:

// foo.h 
class Tester; 
class Foo 
{ 
private: 
    friend class Tester; 
    int private_number_1; 
    int private_function_1() { return 0; } 
}; 

// foo_test.cpp 
#include <cassert> 

class Tester : public Foo 
{ 
public: 
    void test_case_1() { assert(private_number_1 == 0); } 
    void test_case_2() { assert(private_function_1() == 0); } 
}; 

void main() 
{ 
    Tester ff; 
    ff.test_case_1(); 
    ff.test_case_2(); 
} 
0

只是重新標記公私,與訪問是用於測試的評論。

然後在完成後將其重新設置爲隱私。你甚至可以使用#if到 來切換它。

+1

這使得您測試的二進制文件與您提供的二進制文件不同,這在許多環境中都是不可接受的。 –

+0

你確定嗎?你可能是對的,但編寫一個簡單的C++類型編譯器的顯而易見的方式只會將公共/私有檢查放在分析階段。 –

+0

你建議'#if'在'public'和'private'之間切換的事實意味着你必須爲測試和發佈分別進行編譯,不是嗎? –

相關問題