我最近发现了一个令我困惑的函数声明:
void CopyAndBindStaleTables( DescriptorHandle DestHandleStart,
ID3D12GraphicsCommandList* CmdList,
void (STDMETHODCALLTYPE ID3D12GraphicsCommandList::*SetFunc)(UINT, D3D12_GPU_DESCRIPTOR_HANDLE));
所以在这个声明中第三个参数是一个函数指针。但是我很难理解为什么我们需要把类名ID3D12GraphicsCommandList ::放在那里。
有什么想法吗?感谢
答案 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)
因为成员函数指针与函数指针不同,并且成员函数指向一个类中的函数的指针与任何其他类不同。不同的类型需要不同的声明。