比方說,我有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