Calling private method in C++
Asked Answered
H

14

21

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

Hepplewhite answered 29/7, 2011 at 12:33 Comment(6)
call the private method from a public function of the same classDolliedolloff
How did you manage to do it without getting compilation errors?Kolb
With addresses... you can get the address of virtual tables and members by knowing the address of your instance.Hepplewhite
BTW, it's not that you shouldn't call it, just that you necessarily can't.Sonatina
@Luchian: C++ has no knowledge of virtual tables. You're in heavily implementation-specific territory if you want to mess with pointer arithmetic here.Tempietempla
True... I want it to work in VS2008... I didn't say I want it to be portable, just if and how it can be done...Hepplewhite
M
10

#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;
}
Moore answered 29/7, 2011 at 12:41 Comment(16)
What if I've class A { void f() {} };?Didactic
who -1'd me? - the OP said this is purely theoretical!Moore
I didn't but probably because the formatting was off. I fixed it.Sonatina
This is so dirty my eyes are bleeding XDPetree
@Nawaz: #define class struct ?!Moore
@Moore : It would mean bluffing everybody :)Audwen
I'm not suggesting that anyone ever actually DOES this ;)Moore
@Luchian: You were looking for something more hack-ish? Seriously? This is as hack-ish as it gets, and it does almost exactly what you want (there is a problem with private inheritance). No change to the header is needed if you do the #defines in your source file before you #include the header.Ramey
@Pete: One problem is that this changes private inheritance to public inheritance, thereby changing the semantics, and possibly the compilation, of the class.Ramey
@Pete, nonetheless worth +1 as a very evil hack.Ramey
I guess the other way is to #define private protected and then use a derived class for access. The private inheritance semantics are less changed.Moore
These redefines render your entire program UB, and strictly speaking you've changed the type declaration. And writing friend is hardly a hack.Tempietempla
+1 The friend is also nice, but I'm looking for something eviler.Hepplewhite
redefining keywords invokes undefined behaviour.Didactic
This isn't very clever. All he did was use the keyword friend to allow the Hack class to access private members of the class Foo. What you should be thinking about is acquiring the memory address of the private function and calling on it through a pointer.Artery
And how would you do that @KacyRaye, assuming that you cannot directly modify the header that contains Foo? You could write something to post-process a linker generated map file and modify the binary but it seems a little bit overkill? OP did actually ask for a hack..Moore
W
18

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)();
}
Willman answered 30/7, 2011 at 22:47 Comment(8)
interesting, but i get an error: error C2248: 'A::f' : cannot access private member declared in class 'A' on the line template class rob<Af, &A::f>;Hepplewhite
@Luchian MSVC isn't conforming to the Standards then.Willman
Can you post a link to the standard? I feel like the compiler is right in not letting me access &A::f.Hepplewhite
@Johannes Schaub: Nice work. Is there even a more elegant way to achieve the same? Maybe by using the trick you revealed with the private member? I would really appreciate to get it shorter.Nunnery
@mrA see my blog. I posted a better version thereWillman
@Johannes Schaub: Yeah, it works for members. But I can't get it to work for methods.Nunnery
@mrA it should with methods just aswell. If you don't get it to work, i propose you adda new stackoverflow questionWillman
Added a question here: #39648919Nunnery
M
10

#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;
}
Moore answered 29/7, 2011 at 12:41 Comment(16)
What if I've class A { void f() {} };?Didactic
who -1'd me? - the OP said this is purely theoretical!Moore
I didn't but probably because the formatting was off. I fixed it.Sonatina
This is so dirty my eyes are bleeding XDPetree
@Nawaz: #define class struct ?!Moore
@Moore : It would mean bluffing everybody :)Audwen
I'm not suggesting that anyone ever actually DOES this ;)Moore
@Luchian: You were looking for something more hack-ish? Seriously? This is as hack-ish as it gets, and it does almost exactly what you want (there is a problem with private inheritance). No change to the header is needed if you do the #defines in your source file before you #include the header.Ramey
@Pete: One problem is that this changes private inheritance to public inheritance, thereby changing the semantics, and possibly the compilation, of the class.Ramey
@Pete, nonetheless worth +1 as a very evil hack.Ramey
I guess the other way is to #define private protected and then use a derived class for access. The private inheritance semantics are less changed.Moore
These redefines render your entire program UB, and strictly speaking you've changed the type declaration. And writing friend is hardly a hack.Tempietempla
+1 The friend is also nice, but I'm looking for something eviler.Hepplewhite
redefining keywords invokes undefined behaviour.Didactic
This isn't very clever. All he did was use the keyword friend to allow the Hack class to access private members of the class Foo. What you should be thinking about is acquiring the memory address of the private function and calling on it through a pointer.Artery
And how would you do that @KacyRaye, assuming that you cannot directly modify the header that contains Foo? You could write something to post-process a linker generated map file and modify the binary but it seems a little bit overkill? OP did actually ask for a hack..Moore
D
6

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

Didactic answered 29/7, 2011 at 12:45 Comment(3)
I want to do it without changing the class declaration.Hepplewhite
If I can declare the function get(), why not just call f from it?Hepplewhite
Good point but, isn't that too complex compared to just making a public function just call the private onePetree
E
3

The simplest way:

#define private public
#define protected public
Eddyede answered 29/7, 2011 at 13:11 Comment(1)
UB (though, I suppose, I can't imagine a "hack" that wouldn't be, here..). At the very least, it's cheating.Tempietempla
R
3

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.

Ramey answered 29/7, 2011 at 13:37 Comment(0)
Y
2

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?

Ysabel answered 29/7, 2011 at 12:48 Comment(3)
I'm just trying to call the private method... That's it. Without changing the class definition.Hepplewhite
Well, I think friendship is the tool you are looking for, though you do need to change the class declaration for that. You just can't do it using inheritance.Petree
What I'm looking for is a hack. I managed to call a private virtual by getting the address of the vftable and calling the function at that address. I could have done it using friendship, but this is the sort of thing I'm looking for.Hepplewhite
D
1

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

Dolliedolloff answered 29/7, 2011 at 12:41 Comment(0)
C
1

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;
}
Clotilde answered 22/3, 2022 at 20:14 Comment(3)
This is limited to a single method. :(Latium
It may be expanded to some remaining methods via macro, see : github.com/glensand/misc/blob/main/…Clotilde
Another option is to introduce a string name as a yet another template argument, and specify the same string both when instantiating and when calling the method.Latium
A
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").

Angleworm answered 29/7, 2011 at 12:42 Comment(1)
I AM looking for the "evil" way.Hepplewhite
T
0

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.

Tempietempla answered 29/7, 2011 at 13:40 Comment(12)
That's one of the ways to change private members, but I don't see how you can call private methods. This sort of idea is what I'm looking for.Hepplewhite
Fair point. It's as close as you'll get, though (without re-writing the code with #defines, which is definitely cheating).Tempietempla
How? Private members reside in memory, at a specific offset relative to the object's address. Private non-virtual methods are somewhere else (at least that's what the assembler says). If you know how, please post an answer with some code and I will happily accept it. :)Hepplewhite
@Luchian: It doesn't matter where the member function is. When you call it, you pass it (implicitly) a pointer to the object it should work on. By hacking, you can send an object of type A into a member function expecting to work on a type B. This is of arguable benefit in this case, which is why I said "fair point". :)Tempietempla
I know, you actually put the address of this in a registry and the function then works on that... which is like passing the this to the function. That doesn't solve the issue though...Hepplewhite
@Luchian: Registry? No, it's an implicit first argument in the function call. Really, Luchian, there is no "issue" here other than you trying to sidestep every single feature that C++ gives you.Tempietempla
Okay, issue was miss-used. I don't get why you are so against this. Just because you think it's wrong or against C++ or whatever doesn't mean you shouldn't at least think of ways to do it. Think of it as a brain-teaser. If the question annoys you, you don't have to answer it...Hepplewhite
@Luchian: I didn't say that it annoys me, and I did answer it, and I did think of ways to do it. Don't be so defensive. It's not me that's against this; it's the facts of the language.Tempietempla
Ok sorry about that... :) What I did do so far is try to find the address of the function considering the addresses of the functions from the same class, but that didn't work (they appear to be scattered).Hepplewhite
@Luchian: The addresses of functions are not relevant. I suggest ignoring them!Tempietempla
I did some advertisement for my blog. See below.Willman
@Johannes: Stack Overflow is not an advertising space.Tempietempla
A
0

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.

Abreaction answered 29/7, 2011 at 15:5 Comment(0)
A
0

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
}
Anthonyanthophore answered 30/1, 2015 at 0:34 Comment(1)
This only works in x86 programs, you cannot embed assembler in x64 code in MSVC, I think.Valence
C
0

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

Casarez answered 13/8, 2015 at 20:8 Comment(0)
A
0

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;
}
Anschauung answered 18/2, 2023 at 7:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.