为什么定义一个成员函数指针变量需要class名字?

Why defining a member function pointer variable need class name?

我最近发现了一个让我困惑的函数声明:

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

所以在这个声明中第三个参数是一个函数指针。但我很难理解为什么我们需要将 class 名称 ID3D12GraphicsCommandList:: 放在那里。

有什么想法吗?谢谢

因为成员函数指针不同于函数指针,并且指向一个函数的成员函数指针class不同于任何其他class。不同的类型需要不同的声明。

它是一个成员函数指针。这不是直接指向函数的指针,而是关于它的足够信息,结合指向对象的引用或指针,可以调用该函数。 Virtually 如果它是虚拟的。

您可以将其视为 class' vtable 中的一种偏移量(因为大多数现存的 C++ 实现都使用 vtables)。

通常避免使用成员函数指针是个好主意,因为它们很容易在无意中破坏类型系统,而且随后发挥作用的规则非常微妙,即使是专家也不得不三思而后行。 .


这是一个成员函数指针如何允许非常不安全的 hack 的示例,这可能看起来很安全,因为 没有显式类型转换 ,但最终仍然会在失败的情况下崩溃断言。我像往常一样在这段代码中添加了 const (这是一个很好理解的例子),但是所有 const 的东西都可以忽略,删除。这里的问题源于对成员指针的冒险使用,该指针允许通过引用基 class 类型的对象来访问基 class' 受保护的部分:

#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.
}

这是一个示例,说明如何使用相同类型的技巧,但现在用于数据成员,访问 std::stackprotected 集合成员以找到当前堆栈大小:

#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.
}