Able to use pointer to function to call private method of an external class
Asked Answered
R

4

17

Based on the following answer to a recent question, I'm able to use a function pointer in order to call the private method Foo<T>::foo() from another class Bar, as shown below (see also ideone)

#include <iostream>

template<typename T>
struct Bar
{
    typedef void (T::*F)();

    Bar( T& t_ , F f ) : t( t_ ) , func( f )
    {
    }

    void operator()()
    {
        (t.*func)();
    }

    F func;
    T& t;
};

template<typename T>
class Foo
{
private:
    void foo()
    {
        std::cout << "Foo<T>::foo()" << std::endl;
    }

public:    
    Foo() : bar( *this , &Foo::foo ) 
    {
        bar();
    }

    Bar<Foo<T> > bar;
};

int main()
{
    Foo<int> foo;
}

This works on MSVC 2013 and GCC 4.8.3. Is it valid?

Retrospective answered 18/12, 2014 at 0:51 Comment(2)
Sure, why shouldn't it be? Access was checked when the pointer was assigned.Retharethink
This is really no different to going public: void buz() { foo(); }Tamayo
H
9

Yes it is permissible, and it works.

C++ Programming by Bjarne Stroustoup

C++ protects against accident rather than deliberate circumvention (fraud)

Sure, you cannot directly/easily call private methods outside the class, but if you are making enough efforts, C++ will allow it.

Hasan answered 18/12, 2014 at 0:56 Comment(8)
There is no circumventing involved here, it's a straightforward use of a pointer.Retharethink
@Retharethink circumventing against private data members.Hasan
@Retharethink (t.*func)(); -- circumvention, private member--> void foo(). I am missing something?Hasan
@Retharethink You made public to protected member in derived class, OP called private from function. There is a difference.Hasan
Let us continue this discussion in chat.Hasan
@PranitKothari Foo is the one forming a pointer to its private member function, which it's obviously allowed to do. All Bar<Foo<T>> knows is it was passed a pointer to member function that points to something, access control does not come into the picture at that point. You're simply invoking that something by calling Bar::operator()Abrego
@Abrego I didn't say it is not allow. But calling foo like (t.*func)(); , isn't calling to private member of other class?Hasan
Yes, but it's doing so only because it happened to be initialized with a pointer to a private member function. The OP seems confused about how access control works, and your answer implies he's doing something sneaky to circumvent access control, when there's no such thing going on.Abrego
T
21

C++ standard says

11.1 A member of a class can be
(1.1) — private; that is, its name can be used only by members and friends of the class in which it is declared.

i.e. the access specifier is applied to the name, not the executable code. This makes sense if you think about it, since access specifiers are a compile-time construct.

Triboelectricity answered 18/12, 2014 at 1:16 Comment(2)
Yes, for the standard quote.Retharethink
It should be noted that it is the choice of the class Foo to provide the constructor of Bar with the pointer to the function. Without this help from the inside, Bar would not be able to call Foo::foo() from the outside.Mcauley
H
9

Yes it is permissible, and it works.

C++ Programming by Bjarne Stroustoup

C++ protects against accident rather than deliberate circumvention (fraud)

Sure, you cannot directly/easily call private methods outside the class, but if you are making enough efforts, C++ will allow it.

Hasan answered 18/12, 2014 at 0:56 Comment(8)
There is no circumventing involved here, it's a straightforward use of a pointer.Retharethink
@Retharethink circumventing against private data members.Hasan
@Retharethink (t.*func)(); -- circumvention, private member--> void foo(). I am missing something?Hasan
@Retharethink You made public to protected member in derived class, OP called private from function. There is a difference.Hasan
Let us continue this discussion in chat.Hasan
@PranitKothari Foo is the one forming a pointer to its private member function, which it's obviously allowed to do. All Bar<Foo<T>> knows is it was passed a pointer to member function that points to something, access control does not come into the picture at that point. You're simply invoking that something by calling Bar::operator()Abrego
@Abrego I didn't say it is not allow. But calling foo like (t.*func)(); , isn't calling to private member of other class?Hasan
Yes, but it's doing so only because it happened to be initialized with a pointer to a private member function. The OP seems confused about how access control works, and your answer implies he's doing something sneaky to circumvent access control, when there's no such thing going on.Abrego
R
1

Yes, it is valid.

Bar.operator()() is just using a pointer, not trying to use an identifier with private access specifier.
It does not matter how that pointer was initialized, as long as it points to the right function.

As an example, look at this:

#include <iostream>
struct A {
protected:
    void hidden() { std::cout << "But I was hidden !?\n"; }
};
struct B : A {
    using A::hidden; // Making it public
};
int main() {
    B().hidden();
}

As an aside, don't use std::endl unless you really want to flush the stream, as that's expensive.
Normally '\n' suffices.

Retharethink answered 18/12, 2014 at 1:8 Comment(0)
T
0

It does matter.

Header File

class A;
typedef int (A::*handler)(int x);
struct handler_pair {
    int code,
    handler fn
}

class A {
...
private:
  int onGoober(int x);
  int onGomer(int x);
};

Source file

handler_pair handler_map[] = {
    {0, &A::onGoober},          // these will complain about the method being private
    {1, &A::onGomer}
};

Changing the handler_map to a static member in the class and initializing that way avoids the complaint.

Where you take the address of the member function is important.

Tearjerker answered 24/8, 2016 at 19:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.