比方说,我有2个班Instrument
和Brass
,其中Brass
从Instrument
得出:取消引用upcasted成员函数指针
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; }
}
对于一些疯狂的原因,我有一个指针仪表的成员函数:
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
就像我曾呼吁派生类的功能正常。因此,显然上传一个派生类函数指针不会影响在派生类上取消引用时发生的情况(尽管在基类上取消引用会导致未定义的行为)。
编译器如何使这成为可能?
我没有给你答案,只是想说C++函数指针是可怕的。 – zmbq 2014-12-18 22:51:27
一般来说,小心不要将实证结果与正确的行为混为一谈。特别是C++有许多不同类型的未定义(或实现定义的)行为,这些行为会导致从不正确的代码中看似正确的事情(通常这纯粹是巧合)。 – Cameron 2014-12-18 22:52:45
它听起来像你正在手动实施一个vtable? – 2014-12-18 22:57:21