假设我有 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
中不存在的 Brass 成员函数,如下所示:
instrumentAction = static_cast<instrumentVoidFunc>(&Brass::printPitchShifter);
我的理解是(或者无论如何),向上转换成员函数指针应该会破坏它引用基类中尚未存在的派生类函数的任何能力。但是:
Brass trumpet("valves");
(trumpet.*instrumentAction)();
...打印出 valve
就像我正常调用派生类上的函数一样。因此,显然向上转换派生类函数指针不会影响在派生类上取消引用它时发生的情况(尽管在基类上取消引用它会产生未定义的行为)。
编译器到底是如何实现这一点的?
最佳答案
虽然函数指针强制转换是可能的,但通过与原始类型不匹配的函数类型调用函数是未定义的行为。允许函数指针强制转换的原因是支持强制转换并存储公共(public)类型,但通过在调用函数指针之前将函数指针强制转换回来来恢复正确的类型。此限制的基本背景是,即使是兼容的指针也可能需要在使用时进行调整。隐藏正确的签名意味着存在合适的蹦床(即函数指针需要具有附加状态)。
关于c++ - 取消引用向上转换的成员函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27557056/