假设我有2个课程Instrument
和Brass
,其中Brass
来自Instrument
:
class Instrument
{
protected:
std::string _sound;
public:
Instrument(std::string sound) : _sound(sound) {}
virtual void play() { std::cout << _sound << std::endl; }
};
class Brass : public Instrument
{
private:
std::string _pitchShifter;
public:
Brass(std::string pitchShifter) : Instrument("braaaaaa"), _pitchShifter(pitchShifter)
{}
void printPitchShifter() { std::cout << _pitchShifter << std::endl; }
}
出于某些疯狂的原因,我有一个指向Instrument的成员函数的指针:
typedef void(Instrument::*instrumentVoidFunc)() //declaring member function pointers is too damn confusing
instrumentVoidFunc instrumentAction;
现在显然,这将有效,具有明确定义的行为:
Instrument soundMaker("bang!");
instrumentAction = &Instrument::play;
(soundMaker.*instrumentAction)();
输出应为bang!
。
但是我也可以instrumentAction
指向Instrument
中的黄铜成员函数而不是通过向上转换它,如下所示:
instrumentAction = static_cast<instrumentVoidFunc>(&Brass::printPitchShifter);
我的理解是(或者,无论如何)向上转换成员函数指针应该破坏它引用基类中尚不存在的派生类函数的任何能力。但是:
Brass trumpet("valves");
(trumpet.*instrumentAction)();
...打印出valves
就好像我正常地在派生类上调用了函数一样。因此,显然向上转换派生类函数指针不会影响在派生类上取消引用时发生的事情(尽管在基类上取消引用它会产生未定义的行为)。
编译器究竟如何才能实现这一目标?
答案 0 :(得分:3)
虽然可以使用函数指针强制转换,但是通过与原始类型不匹配的函数类型调用函数是未定义的行为。允许函数指针强制转换的原因是支持转换和存储公共类型,但通过在调用之前将函数指针强制转换来恢复正确的类型。这种限制的基本背景是即使是兼容的指针也可能需要在使用时进行调整。隐藏正确的签名意味着存在合适的蹦床(即,函数指针需要具有附加状态)。