Olumide
Olumide

Reputation: 5839

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

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?

Upvotes: 17

Views: 11087

Answers (4)

lkreinitz
lkreinitz

Reputation: 310

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.

Upvotes: 0

sdzivanovich
sdzivanovich

Reputation: 760

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.

Upvotes: 21

Deduplicator
Deduplicator

Reputation: 45704

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.

Upvotes: 1

Pranit Kothari
Pranit Kothari

Reputation: 9859

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.

Upvotes: 9

Related Questions