12

我一直在绞尽脑汁想从 C++ 中的一些测试代码中访问受保护成员函数的最佳方法,这是我的问题:

//in Foo.h 
Class Foo
{
protected:
    void DoSomething(Data data);
}

//in Blah.h
Class Blah
{
public:
    Foo foo;
    Data data; 
};

//in test code...
Blah blah;
blah.foo.DoSomething(blah.data); // Here's my problem!

到目前为止的一些可能的解决方案:

  • 让测试代码类成为 Foo 的朋友,但这会用测试代码污染 Foo
  • 使 DoSomething 成为公共功能
  • 正如本文所建议的,我已经研究过为 Foo 创建一个测试包装器,但是这不起作用,因为 Blah 包含 Foo 的实例。

    欢迎所有建议/见解/意见!

    谢谢

  • 4

    8 回答 8

    18

    有一种标准完全允许的方式。

    //in Foo.h 
    class Foo
    {
    protected:
        void DoSomething(Data data);
    };
    
    //in Blah.h
    class Blah
    {
    public:
        Foo foo;
        Data data; 
    };
    
    //in test code...
    struct FooExposer : Foo {
      using Foo::DoSomething;
    };
    
    Blah blah;
    (blah.foo.*&FooExposer::DoSomething)(blah.data);
    

    阅读C++ 的隐藏特性条目以获得解释。


    为了方便起见,您可以编写一个宏(括号在那里,以便您可以将此宏也用于具有逗号的类型,例如vector<pair<A, B>>):

    #define ACCESS(A, M, N) struct N : get_a1<void A>::type { using get_a1<void A>::type::M; }
    
    template<typename T> struct get_a1;
    template<typename R, typename A1> struct get_a1<R(A1)> { typedef A1 type; };
    

    现在事情变成了

    ACCESS((Foo), DoSomething, GetDoSomething);
    Blah blah;
    (blah.foo.*&GetDoSomething::DoSomething)(blah.data);
    
    于 2009-11-12T20:24:23.160 回答
    8

    好的,既然你说它只是一个测试代码,我将建议一些非常hacky但会起作用的东西:

    struct tc : protected Foo
    {
        tc(Foo *foo, Data& data)
        {
            ((tc*)foo)->DoSomething(data);
        }
    };
    
    Blah blah;
    tc t(&blah.foo, blah.data);
    
    于 2009-11-12T17:52:37.753 回答
    7

    一方面,不要那样做

    另一方面,这是一场赌博:

    #define protected public
    #include "foo.h"
    #undef protected
    

    8-)

    但说真的,为什么要DoSomething()受到保护?可能是因为从外部代码调用它会破坏某些东西。在这种情况下,您不应该从测试中调用它。

    于 2009-11-12T17:34:56.077 回答
    3

    而不是 ifdefing privateto public,考虑ifdefing friendly,或者更好地考虑该函数是否真的需要属于该类,也许在 cpp 的命名/未命名命名空间中有一些东西就足够了,然后在测试项目中声明。

    无论如何,请检查链接,也许您的测试框架会提供类似的功能。

    编辑:您是否考虑过从您的真实班级继承您的测试班?

    于 2009-11-12T17:46:49.203 回答
    3

    我已经搞定了

    class Foo
    {
    protected:
        void DoSomething(Data data);
    public:
        #ifdef TEST
        void testDoSomething(Data data);
        #endif
    }
    

    然后用 g++ -D TEST 编译你的单元测试。

    于 2009-11-12T17:44:06.040 回答
    2

    按如下方式使用包装器:

    // Foo.h unchanged
    
    // Blah.h unchanged
    
    // test code
    class FooTest : public Foo { friend void test(); }; // make friends
    
    void test()
    {
        Blah blah;
        static_cast<FooTest*>(&blah.foo)->DoSomething(blah.data); // Here's no problem!    
    }
    
    于 2009-11-12T19:51:25.983 回答
    2

    您可以将继承与转发功能一起使用:

    class Foo
    {
    protected:
        void DoSomething(Data data);
    }
    
    class test_Foo : public Foo
    {
    public:
        void testDoSomething(Data data)
        {
            DoSomething(data);
        }
    }
    
    于 2009-11-12T19:40:05.700 回答
    1

    如果它是严格的测试代码,你可以这样做......

    #define protected public
    #include "Foo.h"
    
    // test code
    
    #undef protected
    
    于 2009-11-12T17:36:15.120 回答