开发者

Calling private method in C++

开发者 https://www.devze.com 2023-03-23 15:36 出处:网络
This is开发者_如何学运维 purely a theoretical question, I know that if someone declares a method private, you probably shouldn\'t call it. I managed to call private virtual methods and change private

This is开发者_如何学运维 purely a theoretical question, I know that if someone declares a method private, you probably shouldn't call it. I managed to call private virtual methods and change private members for instances, but I can't figure out how to call a private non-virtual method (without using __asm). Is there a way to get the pointer to the method? Are there any other ways to do it?

EDIT: I don't want to change the class definition! I just want a hack/workaround. :)


See my blog post. I'm reposting the code here

template<typename Tag>
struct result {
  /* export it ... */
  typedef typename Tag::type type;
  static type ptr;
};

template<typename Tag>
typename result<Tag>::type result<Tag>::ptr;

template<typename Tag, typename Tag::type p>
struct rob : result<Tag> {
  /* fill it ... */
  struct filler {
    filler() { result<Tag>::ptr = p; }
  };
  static filler filler_obj;
};

template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;

Some class with private members

struct A {
private:
  void f() {
    std::cout << "proof!" << std::endl;
  }
};

And how to access them

struct Af { typedef void(A::*type)(); };
template class rob<Af, &A::f>;

int main() {
  A a;
  (a.*result<Af>::ptr)();
}


#include the header file, but:

#define private public
#define class struct

Clearly you'll need to get around various inclusion guards etc and do this in an isolated compilation unit.

EDIT: Still hackish, but less so:

#include <iostream>

#define private friend class Hack; private

class Foo
{
public:
    Foo(int v) : test_(v) {}
private:
    void bar();
    int test_;
};
#undef private
void Foo::bar() { std::cout << "hello: " << test_ << std::endl; }

class Hack
{
public:
    static void bar(Foo& f) {
        f.bar();
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Foo f(42);
    Hack::bar(f);
    system("pause");
    return 0;
}


It can be called if a public function returns the address of the private function, then anyone can use that address to invoke the private function.

Example,

class A
{
   void f() { cout << "private function gets called" << endl; }
 public:
     typedef void (A::*pF)();
     pF get() { return &A::f; }
};

int main() 
{
        A a;
        void (A::*pF)() = a.get();
        (a.*pF)(); //it invokes the private function!
}

Output:

private function gets called

Demo at ideone : http://www.ideone.com/zkAw3


The simplest way:

#define private public
#define protected public


Followup on T.E.D.'s answer: Don't edit the header. Instead create your own private copy of the header and insert some friend declarations in that bogus copy of the header. In your source, #include this bogus header rather than the real one. Voila!

Changing private to public might change the weak symbols that result from inlined methods, which in turn might cause the linker to complain. The weak symbols that result from inline methods will have the same signatures with the phony and real headers if all that is done is to add some friend declarations. With those friend declarations you can now do all kinds of evil things with the class such as accessing private data and calling private members.

Addendum
This approach won't work if the header in question uses #pragma once instead of a #include guard to ensure the header is idempotent.


You have friend classes and functions.

I know that if someone declares a method private, you probably shouldn't call it.

The point is not 'you shouldn't call it', it's just 'you cannot call it'. What on earth are you trying to do?


Call the private method from a public function of the same class.


Easiest way to call private method (based on previous answers but a little simpler):

// Your class
class sample_class{
    void private_method(){
        std::cout << "Private method called" << std::endl;
    }
};

// declare method's type
template<typename TClass>
using method_t = void (TClass::*)();

// helper structure to inject call() code
template<typename TClass, method_t<TClass> func>
struct caller{
    friend void call(){
        TClass obj;
        (obj.*func)();
    }
};

// even instantiation of the helper
template struct caller<sample_class,&sample_class::private_method>;

// declare caller
void call();

int main(){
    call(); // and call!
    return 0;
}


Well, the obvious way would be to edit the code so that it is no longer private.

If you insist on finding an evil way to do it...well...with some compilers it may work create your own version of the header file where that one method is public instead of private. Evil has a nasty way of rebounding on you though (that's why we call it "evil").


I think the closest you'll get to a hack is this, but it's not just unwise but undefined behaviour so it has no semantics. If it happens to function the way you want for any single program invocation, then that's pure chance.


Define a similar class that is the same apart from the function being public.

Then typecast an object with the private function to one with the public function, you can then call the public function.


If we are speaking of MSVC, I think the simplest way with no other harm than the fact of calling a private method itself is the great __asm:

class A
{
private:
    void TestA () {};
};

A a;
__asm
{
    // MSVC assumes (this) to be in the ecx.
    // We cannot use mov since (a) is located on the stack
    // (i.e. [ebp + ...] or [esp - ...])
    lea     ecx, [a]
    call    A::TestA
}


For GCC it can be done by using mangled name of a function.

#include <stdio.h>

class A {
public:
    A() {
        f(); //the function should be used somewhere to force gcc to generate it
    }
private:
    void f() { printf("\nf"); }
};

typedef void(A::*TF)();

union U {
    TF f;
    size_t i;
};

int main(/*int argc, char *argv[]*/) {
    A a;
    //a.f(); //error
    U u;
    //u.f = &A::f; //error

    //load effective address of the function
    asm("lea %0, _ZN1A1fEv"
    : "=r" (u.i));
    (a.*u.f)();
    return 0;
}

Mangled names can be found by nm *.o files.

Add -masm=intel compiler option

Sources: GCC error: Cannot apply offsetof to member function MyClass::MyFunction https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html


After reading Search for an elegant and nonintrusive way to access private methods of a class, I want to sum up an ideal way since no one else has pasted it here:

// magic
//

template <typename Tag, typename Tag::pfn_t pfn>
struct tag_bind_pfn
{
    // KEY: "friend" defines a "pfn_of" out of this template. And it's AMAZING constexpr!
    friend constexpr typename Tag::pfn_t pfn_of(Tag) { return pfn; }
};

// usage
//

class A
{
    int foo(int a) { return a; }
};

struct tag_A_foo
{
    using pfn_t = int (A::*)(int);
    // KEY: make compiler happy?
    friend constexpr typename pfn_t pfn_of(tag_A_foo);
};
// KEY: It's legal to access private method pointer on explicit template instantiation
template struct tag_bind_pfn<tag_A_foo, &A::foo>;

inline static constexpr const auto c_pfn_A_foo = pfn_of(tag_A_foo{});

#include <cstdio>

int main()
{
    A p;
    auto ret = (p.*(c_pfn_A_foo))(1);
    printf("%d\n", ret);
    return 0;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消