Luchian Grigore
Luchian Grigore

Reputation: 258548

Calling private method in C++

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. :)

Upvotes: 21

Views: 47405

Answers (14)

Hsu Pu
Hsu Pu

Reputation: 83

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;
}

Upvotes: 0

Gleb Bezborodov
Gleb Bezborodov

Reputation: 66

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;
}

Upvotes: 1

bartolo-otrit
bartolo-otrit

Reputation: 2509

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

Upvotes: 0

Kde
Kde

Reputation: 87

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
}

Upvotes: 0

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506847

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)();
}

Upvotes: 18

QuentinUK
QuentinUK

Reputation: 3077

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.

Upvotes: 0

David Hammen
David Hammen

Reputation: 33106

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.

Upvotes: 3

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385098

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.

Upvotes: 0

Pete
Pete

Reputation: 4812

#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;
}

Upvotes: 10

legendlee
legendlee

Reputation: 578

The simplest way:

#define private public
#define protected public

Upvotes: 3

Antonio P&#233;rez
Antonio P&#233;rez

Reputation: 6962

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?

Upvotes: 2

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361282

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

Upvotes: 6

T.E.D.
T.E.D.

Reputation: 44794

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").

Upvotes: 0

ascanio
ascanio

Reputation: 1526

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

Upvotes: 1

Related Questions