C ++:对不同派生类对象的基指针调用(派生的)成员函数 [英] C++: call (derived's) member function on base pointer of a different derived class's object
问题描述
是安全(和/或可移植)调用基类指针上的成员函数(指针),但指向的对象是实例不同的派生类。成员函数不访问派生类的任何成员变量或函数。
Is it "safe" (and/or portable) to call a member function (pointer) on the pointer of a base class, but the object pointed to is an instance different derived class. The member function does not access any member variables or functions of the derived class.
/* Shortened example of what happens in the client code and library */
class Base { /* ... */ }
class DerivedA : public Base {
/* ... */
public: void doSomethingA(float dt);
}
void DerivedA::doSomethingA(float dt) {
/* Does not access members. Conventionally calls/accesses statics */
cout << "dt(" << dt << ")";
}
class DerivedB : public Base { /* ... */ }
typedef void (Base::*SEL_SCHEDULE)(float);
SEL_SCHEDULE pCallback = (SEL_SCHEDULE)(&DerivedA::doSomethingA);
DerivedB db = new DerivedB();
Base *b = &db;
/* pCallback and b are saved in a list elsewhere (a scheduler) which calls */
(b->*pCallback)(0.f);
这个似乎工作(在MSVC / Debug模式) ,但我想知道这是否是Bad(TM) - 为什么? (我还没有用Android和iOS的编译器测试这个代码)。
This seems to work (in MSVC/Debug mode) okay at runtime, but I'm wondering whether this is Bad (TM) - and why? (I'm yet to test this code with the compilers for Android and iOS).
一些更多的细节,如果需要:我建立一个 cocos2d-x 项目。 Base
是 CCObject
, DerivedA
和 DerivedB
是 CCLayer
。
Some more specifics if required: I'm building a cocos2d-x based project. Base
is CCObject
, DerivedA
and DerivedB
are subclasses of CCLayer
.
层次结构是 DerivedA
和 DerivedB
< CCLayer
< CCNode
< CCObject
。
The hierarchy is DerivedA
and DerivedB
< CCLayer
< CCNode
< CCObject
. They're game scenes which are visible/alive at mutually exclusive times.
DerivedA
有不同的设置音乐播放的静态功能,它接收 CCNode
调用者对象作为参数和 schedule 另一个 selector ( doSomethingA
)到开始播放, / em>使用类似:
DerivedA
has a different static function to set up playback of music which receives a CCNode
caller object as a parameter and schedules another selector (doSomethingA
) to begin playback and slowly fade it in using something like:
callerNode->schedule(schedule_selector(DerivedA::doSomethingA), 0.05f);
schedule_selector
是C风格的。 doSomethingA
不访问其任何成员变量或调用成员函数。它访问静态成员,并调用其他静态函数,例如例如
schedule_selector
is what does the C-style cast. doSomethingA
does not access any of its member variables or call member functions. It accesses static members and calls other static functions such as such as
CocosDenshion::SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(sFadeMusicVolume);
在运行时调用 doSomethingA
CCTimer :: update 。
主要是为了避免重复的代码,并符合库的回调签名(timer / scheduler system)。
The hack is primarily to avoid duplicating code and conform to the library's callback signature (timer/scheduler system).
推荐答案
这是UB。
你甚至可以使用static_cast而不是可恶的C风格的cast,本身是相当合法的。但
You can even use static_cast instead of the odious C-style cast, and the cast itself is quite legal. But
[注意:尽管类B不需要包含原始成员,
动态类型的对象到成员是
dereferenced必须包含原始成员;见5.5。 -end note](5.2.9 12)
[Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5. —end note ] (5.2.9 12)
第一个操作数称为对象表达式,如果对象表达式的动态
类型不包含
指针指向的成员,行为未定义(5.5 4)
"The first operand is called the object expression. If the dynamic type of the object expression does not contain the member to which the pointer refers, the behavior is undefined" (5.5 4)
你可以从一个动态类型DerivedB的对象调用它。
I.e., you go undefined when you call it from an object of dynamic type DerivedB.
现在,随着脏的hacks走,它可能不是最糟糕的(比手动遍历vtables更好)是真的需要吗?如果你不需要任何动态数据,为什么在DerivedB上调用它? Base在库中,你不能重新定义它。回调也是库管理员,所以你必须有这个 typedef void(Base :: * SEL_SCHEDULE)(float);
,OK。但是为什么不能为B定义 doSomething
,并使指针指向它与DerivedB的实例耦合?您说
Now, as a dirty hacks goes, it's probably not the worst (better than the manual traversing of vtables), but is it really needed? If you don't need any dynamic data, why call it on DerivedB? Base is in the library, you cannot redefine it. Callback is librarian, too, so you have to have this typedef void (Base::*SEL_SCHEDULE)(float);
, OK. But why can't you define doSomething
for B and make pointer to it to couple with an instance of DerivedB? You say
doSomethingA不访问其任何成员变量或调用
成员函数。它访问静态成员并调用其他静态
函数
doSomethingA does not access any of its member variables or call member functions. It accesses static members and calls other static functions
但是你可以在 doSomethingB
。或者,如果你的回调从对象类型完全解开,并且你需要一个成员函数指针的唯一原因是符合库回调签名,你可以使你的实际回调非成员简单的老函数,行成员 - DoSomething(float dt){ReallyDoSomething(dt);}
的回调构象。
But you can do it in doSomethingB
as well. Or, if your callbacks are completely uncoupled from object types, and the only reason you need a member function pointer is the conformance to the library callback signature, you can make your actual callbacks non-member plain old functions, and call them from one-line members-callback conformers like DoSomething(float dt) {ReallyDoSomething(dt);}
.
这篇关于C ++:对不同派生类对象的基指针调用(派生的)成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!