为什么定义成员函数指针变量需要类名?

时间:2016-03-30 21:34:28

标签: c++ compiler-errors function-pointers member-function-pointers

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

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

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

有什么想法吗?感谢

2 个答案:

答案 0 :(得分:1)

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

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

避免使用成员函数指针通常是一个好主意,因为它们很容易无意中破坏类型系统,然后发挥作用的规则是如此微妙,甚至专家也要三思而后行。< / p>

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

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

以下是一个示例,说明如何使用相同类型的技巧,但现在可以使用数据成员,访问protected的{​​{1}}集合成员以查找当前堆栈尺寸:

std::stack

答案 1 :(得分:0)

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