Peng
Peng

Reputation: 23

Why defining a member function pointer variable need class name?

I recently found a function declaration which confuses me:

void CopyAndBindStaleTables( DescriptorHandle DestHandleStart,
                             ID3D12GraphicsCommandList* CmdList, 
                             void (STDMETHODCALLTYPE  ID3D12GraphicsCommandList::*SetFunc)(UINT, D3D12_GPU_DESCRIPTOR_HANDLE));

So in this declaration the third parameter is a function pointer. But I have a hard time understand why we need to put the class name ID3D12GraphicsCommandList:: there.

Any idea? Thanks

Upvotes: 2

Views: 105

Answers (2)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145269

It's a member function pointer. Which is not directly a pointer to a function, but sufficient info about it that combined with a reference or pointer to object, the function can be called. Virtually if it's virtual.

You can think of it as a kind of offset in a class' vtable (since most every extant C++ implementation uses vtables).

It's generally a good idea to avoid using member function pointers because they make it easy to inadvertently break the type system, and the rules that come into play then are so subtle that even experts have to think twice and look it up.


Here's an example of how member function pointers allow a very unsafe hack, that might look safe because there is no explicit type cast, but that still ends up crashing in a failed assertion. I added const as usual in this code (it's a pretty construed example), but all the const stuff can just be ignored, removed. The problem here stems from a risky use of a member pointer that allows access to a base class' protected parts via a reference to an object of base class type:

#include <string>
using namespace std;

class Collection
{
private:
    int n_items_{ 0 };

protected:
    auto n_items_value() const -> int { return n_items_; }
    auto n_items_var() -> int& { return n_items_; }

public:
    virtual auto n_items() const
        -> int
    { return n_items_; }

    virtual ~Collection() = 0;
};

Collection::~Collection() {}

class List
    : public Collection
{
private:
    mutable bool is_spliced_{ false };

    void count_the_items() { n_items_var() = 42; }

public:
    auto n_items() const
        -> int override
    {
        if( is_spliced_ )
        {
            const_cast<List*>( this )->count_the_items();
            is_spliced_ = false;
        }
        return n_items_value();
    }

    void splice() { is_spliced_ = true; }
};

namespace impl {
    struct Ungood_hack
        : Collection
    {
        // Look ma! No virtual call overhead! Yay!
        static auto fast_n_items( Collection const& o )
            -> int
        {
            return (o.*&Ungood_hack::n_items_value)();
        }
    };
}  // namespace impl

auto fast_n_items( Collection const& o )
    -> int
{ return impl::Ungood_hack::fast_n_items( o ); }

#include <assert.h>
auto main() -> int
{
    List o;
    o.splice();
    #ifdef TEST_IT
        (void) o.n_items();     // Updates the count.
    #endif
    assert( fast_n_items( o ) == 42 );      // !Oops.
}

Here's an example of how the same kind of trick, but now for a data member, can be used to advantage, accessing the protected collection member of a std::stack in order to find the current stack size:

#include <stack>
using namespace std;

template< class Type >
auto n_items( stack<Type> const& st )
    -> int
{
    struct Hack: stack<Type>
    {
        static auto n_items( stack<Type> const& st )
            -> int
        { return (st.*&Hack::c).size(); }
    };

    return Hack::n_items( st );
}

#include <assert.h>
auto main() -> int
{
    stack<int> st;
    st.push( 1 ); st.push( 2 ); st.push( 3 );
    assert( n_items( st ) == 3 );       // OK.
}

Upvotes: 2

Edward Strange
Edward Strange

Reputation: 40859

Because member function pointers are different from function pointers and member function pointers to functions in one class are different from any other class. Different types need different declarations.

Upvotes: 0

Related Questions