为什么定义一个成员函数指针变量需要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::stack
的 protected
集合成员以找到当前堆栈大小:
#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.
}
我最近发现了一个让我困惑的函数声明:
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::stack
的 protected
集合成员以找到当前堆栈大小:
#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.
}