在C++中,可以使用成员函数指针指向派生(甚至是基类)类成员吗?
编辑:也许一个例子会有所帮助.假设我们有三个类的层次结构X,Y,Z在继承顺序.
Y因此有一个基类X和一个派生类Z.
现在我们可以p为类定义一个成员函数指针Y.这写成:
void (Y::*p)();
Run Code Online (Sandbox Code Playgroud)
(为简单起见,我假设我们只对带签名的函数感兴趣void f())
此指针p现在可用于指向类的成员函数Y.
这个问题(两个问题,真的)是:
p用来指向派生类中的函数Z吗?p用来指向基类中的函数X吗?指针只是一个地址吗?或者我错过了什么?
我测试了几种类型的指针:
但是指向成员函数的指针更大 - 我的平台上有16B.
三件事:
void*必须能够"包含"任何指针类型.换句话说,任何指针必须能够被转换为void*,对吧?如果是这样,那么为什么sizeof( void* )是8,而sizeof指向成员函数的指针是16?在C++中,可以获得指向类的(非静态)成员函数的指针,然后在对象上调用它.如果函数是虚函数,则根据对象的动态类型动态调度调用.通过显式提供包含要使用的版本的范围,也可以(不使用成员指针)以单态方式调用对象的虚拟成员函数.以下代码演示了这一点:
#include <iostream>
using std::cout; using std::endl;
struct Foo
{
virtual void foo() { cout << 1 << endl; }
};
struct Foo2: public Foo
{
virtual void foo() { cout << 2 << endl; }
};
int main( int, char** )
{
Foo *foo = new Foo2;
void (Foo::*foo_pointer)() = &Foo::foo;
foo->foo(); // prints 2
foo->Foo::foo(); // prints 1
(foo->*foo_pointer)(); // prints 2
}
Run Code Online (Sandbox Code Playgroud)
我想要做的是将两者结合起来,并获得指向成员函数的单态版本的指针; 即,我想要一个指向Foo :: foo的指针,它总是调用foo的基类版本,并打印1,即使它是在Foo2上调用的.但是,我还没有找到办法做到这一点.可能吗?
(除了编写一个新的非虚函数的繁琐的手动方式,它进行单态调用,然后获得指向它的指针.)
考虑以下C++代码:
class A
{
public:
virtual void f()=0;
};
int main()
{
void (A::*f)()=&A::f;
}
Run Code Online (Sandbox Code Playgroud)
如果我不得不猜测,我会说在这个上下文中的&A :: f将意味着"A的f()实现的地址",因为在指向常规成员函数和虚拟成员函数的指针之间没有明确的分离.由于A没有实现f(),这将是一个编译错误.但事实并非如此.
不仅如此.以下代码:
void (A::*f)()=&A::f;
A *a=new B; // B is a subclass of A, which implements f()
(a->*f)();
Run Code Online (Sandbox Code Playgroud)
实际上会调用B :: f.
怎么会发生?
我在使用C++函数指针时遇到问题.这是我的例子:
#include <iostream>
using namespace std;
class bar
{
public:
void (*funcP)();
};
class foo
{
public:
bar myBar;
void hello(){cout << "hello" << endl;};
};
void byebye()
{
cout << "bye" << endl;
}
int main()
{
foo testFoo;
testFoo.myBar.funcP = &byebye; //OK
testFoo.myBar.funcP = &testFoo.hello; //ERROR
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Compilator在testFoo.myBar.funcP = &testFoo.hello;以下位置返回错误:
ISO C++禁止获取绑定成员函数的地址以形成指向成员函数的指针.说'&foo :: hello'
无法在赋值时将'void(foo :: )()'转换为'void()()'
所以我试着这样:
class bar
{
public:
void (*foo::funcP)();
};
Run Code Online (Sandbox Code Playgroud)
但是现在编译器增加了一个:
'foo'尚未宣布
有没有办法让它发挥作用?
提前感谢您的建议
在得到这个问题的答案后,我发现有两种有效的方法可以输入一个函数指针.
typedef void (Function) ();
typedef void (*PFunction) ();
void foo () {}
Function * p = foo;
PFunction q = foo;
Run Code Online (Sandbox Code Playgroud)
我现在更喜欢Function * p,PFunction q但显然这对指针到成员函数不起作用.考虑这个人为的例子.
#include <iostream>
struct Base {
typedef void (Base :: *Callback) ();
//^^^ remove this '*' and put it below (i.e. *cb)
Callback cb;
void go () {
(this->*cb) ();
}
virtual void x () = 0;
Base () {
cb = &Base::x;
}
};
struct D1 : public …Run Code Online (Sandbox Code Playgroud) c++ typedef compiler-errors member-function-pointers function-pointers
我试图找出一种方法,如何能够为具有不同数量的参数的函数分配函数指针.
我有一个while循环,它将许多不同的函数作为一个条件语句,所以我没有用完全相同的代码编写多个while循环,而是希望有一个带有函数指针的函数.所有功能都是格式化的bool f(...).我认为一些代码最能说明我的意思:
int a, b, c, d;
MyClass* my_class;
typedef bool (MyClass::*my_fun_t)();
my_fun_t my_fun;
if (condition1)
my_fun = &MyClass::function_one();
else if (condition2)
my_fun = &MyClass::function_two(a, b);
else if (condition3)
my_fun = &MyClass::function_three(a, b, c);
else if (condition4)
my_fun = &MyClass::function_four(a, b, c, d);
while ((my_class->*my_fun)())
{ ... }
Run Code Online (Sandbox Code Playgroud)
现在这显然不起作用,因为函数具有不同的签名.是否可以以类似的方式使其工作?我应该看一下functoids吗?
请考虑以下代码:
template <class>
struct test: std::integral_constant<int, 0> {};
template<class R, class C, class... Args>
struct test<R(C::*)(Args...)>: std::integral_constant<int, 1> {};
template<class R, class C, class... Args>
struct test<R(*C::*)(Args...)>: std::integral_constant<int, 2> {};
template<class R, class C, class... Args>
struct test<R(**C::*)(Args...)>: std::integral_constant<int, 3> {};
template<class R, class C, class... Args>
struct test<R(C::**)(Args...)>: std::integral_constant<int, 4> {};
template<class R, class C, class... Args>
struct test<R(C::***)(Args...)>: std::integral_constant<int, 5> {};
Run Code Online (Sandbox Code Playgroud)
我绝对没有什么想法(*C::*),(**C::*),(C::**)和(C::***)的意思.我想的一个例子test<decltype(f)>,其value将等于2,3, …
如果C++ FAQ Lite中的以下内容为真:"函数名称衰减到指向函数的指针"(因为数组名称衰减为指向其第一个元素的指针); 为什么我们必须加入&符号?
typedef int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = &Fred::f;
Run Code Online (Sandbox Code Playgroud)
而不只是:
typedef int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = Fred::f;
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,Fred :: f是一个函数,可以衰减到指向该函数的指针.
我希望这个问题不是那么愚蠢.
任何人都可以解释为什么编译器(g ++,visual c ++)在这种情况下无法推断模板参数?
struct MyClass
{
void Foo(int x)& {}
void Foo(int x)&& {}
};
template<typename T>
void CallFoo(void(T::*func)(int)&)
{
//create instance and call func
}
int main()
{
CallFoo(&MyClass::Foo); // Fails to deduce T
}
Run Code Online (Sandbox Code Playgroud)
为什么编译器不能将T推导为MyClass?这仅适用于ref限定符重载的方法.如果方法被const-ness或参数类型重载,一切正常.在这种情况下,似乎只有Clang才能推断T.