1

Say I have the following:

class A {
private:
    int a;
    virtual int f() {return a;}
public:
    A(int t) {a = t;}
};

Now, how do I access int A::f() if I am given a pointer to an A object? I know how to get a!

void main () {
    A* x = new A(5);
    cout << ((int*)x)[2]; // returns 5;
}

But now sure how to run A::f().

UPDATE: I know this is not a good design, and privates as supposed to be hidden. The question is just to know how the class is put in memory in the compiler.

sixer24
  • 26
  • 1
  • 4
  • 1
    What problem are you trying to solve? The hacky solution would be implementation defined - finding the vtable pointer and then finding the correct table entry. – Drew Dormann Feb 24 '15 at 21:54

3 Answers3

5

I know how to get a!

A* x = new A(5);
cout << ((int*)x)[2]; // returns 5;

This is such a hack! Nearly as non-portable as it gets, this code causes undefined behavior that happens to produce the result that you expect. It does not mean that it would produce the same result on another system, or even on the same system when the compiler chooses to implement the class differently.

There is no way to access a private function, unless someone hands you a pointer to member function referencing it, or declares your function a friend:

class A;
typedef  int (A::*FPTR)();
class A {
private:
    int a;
    virtual int f() {return a;}
public:
    A(int t) {a = t;}
    FPTR get_private() { return &A::f; }
};
int main() {
    A a(123);
    FPTR fp = a.get_private();
    int res = (a.*fp)();
    cout << res << endl;
    return 0;
}

Demo.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

Hmpf again. The private parts of a class are meant to be private. That means, only accessible by methods of that class, and not by others.

If you want to break this, you can for sure, but you then break also the implementors idea of the interface he wants to present...

pbhd
  • 4,384
  • 1
  • 20
  • 26
  • Maybe you should think about, for example, unit tests, where it is crucial to access private parts sometimes, but I presume you are going always by the book – newhouse Dec 04 '17 at 07:01
  • For unittests its accepted practice to have a good friend, e.g. the Fixture-class or something else depending on the framework you are using. – pbhd Dec 28 '17 at 11:37
1

Trick for the data

Your trick is based on assumptions on the memory layout of your object. Fortunately for your specifi example , with your compiler, it seems to work.

If I compile this code with MSVC2013 it doesn't work at all !! I could eventually find out that it works when I use an array of short instead of int, if I'd put some hints in the constructor:

A(int t) { a = t; cout << "A: " << (void*)this << " a: " << (void*)&a << " rel:" << (char*)&a - (char*)this << endl; }

Conclusion: You can't rely on this in general (an not even for your compiler in more complex examples). The standard gives very limited ensurance about relative memory addresses of members:

Section 9.2/15: Nonstatic data members of a (non-union) class with the same access control are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; (...)

In addition your trick might create pointer aliasing. So the compiler makes assumption about your pointers and the members of your object which might not be valid, causing generated optimisations to fail.

Trick for the functions

For the address of your function, it's even worse. This again is not defined in the standard and is implementation specific.

The commonly used implementation for virtual functions is base on class specific vtables. Each polymorphic object has somewhere in the class a pointer to its vtable (usually in the first fewbytes of the object.

The relative position of function pointer in the vtable depends on all the virtual functions of the class and all the inherited classes. For your example, with MSVC2013 I could manage to call the function:

typedef int (A::*fptr)();
fptr pf = (*(fptr**)x)[0];  // first unction in vtable
(x->*pf)();  // call it. 

But of course this is totally non-standard and extremely dangerous !

And keep in mind that for non virtual functions, you can't get the address from the object at all.

Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138