0

I am developing code that solves about 100 equations. Most of theses equations are computed in private members, because in the end the user doesn't care about them. But, right now I do. So, as I develop the code I would like to have a quick way to test private members.

The code below gives the basic behavior that I want, but it does not work (privacy issue). If this behavior is possible, I would appreciate any help.

// Includes
#include <stdio.h>

// I want a general test class that can access private members
template <class Name> class TestClass{
    public:
        TestClass(Name& input) : the_class(input){}
        Name& operator()(){ return the_class; }
        Name& the_class;
};

// The class I want to test
class ClassA{
    public:
        friend class TestClass<ClassA>; // I hoped this would do it, but it doesn't
        ClassA(){}              
    private:
        void priv(){ printf("a private function\n"); }
};


// Main function that preforms the testing
int main (){
    ClassA a;
    TestClass<ClassA> b(a);
    b().priv(); // I want to do this
}
slaughter98
  • 1,759
  • 14
  • 20
  • 1
    http://stackoverflow.com/questions/729363/is-it-possible-to-access-private-members-of-a-class?lq=1 – kennytm Jul 13 '12 at 18:27
  • Thanks for the link, it looks like I should avoid the whole thing and write a proper test function otherwise I will get in trouble;-) – slaughter98 Jul 13 '12 at 18:49

2 Answers2

1

You've granted friendship to TestClass<ClassA>, but you are asserting that friendship in main() instead.

Your choices are:

  • Write a forwarding function in TestClass<> that invokes the_class.priv()
  • Grant friendship to the function that actually requires it. (I imagine this isn't really main() in your actual program.)
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • Wow. That's crazy. Making main a friend... but I suppose it would work. nice. – Rafael Baptista Jul 13 '12 at 18:40
  • Granting friendship to `main` might be tricky, as there is no *single* definition of what `main` looks like: `int main()`, `int main( int, char** )`... are all valid, which one will you befriend? On the other hand, the test probably runs in a function other than `main` – David Rodríguez - dribeas Jul 13 '12 at 18:54
1

There are different approaches to this. From a high level perspective, you can provide the same functions in the TestClass adapter that are present in the tested type and have it forward the requests. Another option is befriending a test class that will actually perform the tests in member functions.


The code below does not compile, it shows the approach to take, but the details are off. Read the article that Kerrek linked in the comment for more details


Finally, if you want to abuse your C++-fu, you can break access specifiers by using explicit template instantiations and member pointers (I am writing this off the top of my head, it might not compile, but the idea is there... just fight the compiler errors if they come):

template <typename T, void (T::*Ptr)() >
struct accessor {
   typedef void (T::*ptr_t)();
   static ptr_t ptr;
};
template <typename T, void (T::*Ptr)() >
accessor<T,Ptr>::ptr_t accessor<T,Ptr>::ptr = Ptr;

template accessor<ClassA, &ClassA::priv>;
typedef accessor<ClassA, &ClassA> priv_accessor;
int main() {
   ClassA a;
   (a.*priv_accessor::ptr)();
}

The approach here uses template instantiations to break access, as the arguments to the template explicit instantiation don't check access (it would be impossible to instantiate that template with a private member otherwise, as explicit template instantiations must happen at namespace level, and you cannot befriend a namespace)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • This doesn't really work. The idea is correct, but the implementation needs to be a lot more involved. Your typedef doesn't work and can never work (on a conforming compiler); you'll actually need to *store* the member pointer somewhere. (E.g. [see here](http://bloglitb.blogspot.fr/2011/12/access-to-private-members-safer.html)) – Kerrek SB Mar 24 '14 at 14:09
  • @KerrekSB: You are right in that this does not work (I had not attempted to compile it), but the problem is not storing the pointer to member (that is done in the answer), but providing an accessor to extract it *without* naming the template --since anywhere other than the explicit instantiation `&ClassA::priv` will cause a compiler error. Given that you provided a link to a nice article explaining the technique, I am not going to extend the question here. – David Rodríguez - dribeas Mar 25 '14 at 02:53