On 28.07.2014 21:21, pulkomandy wrote:
The second strategy used at Be comes in when we run out of reserved fields. It is a bit less flexible. Many classes define a virtual method called Perform. This method takes a "perform code", and, when used, it looks like this: void A::Perform(int opcode, void* args) { switch(opcode) { case OP_DOSOMETHING: DoSomething(args); return; // more cases } } This can emulate the behavior of virtual methods (you can override Perform, and have it call other methods in subclasses for some ops). It replaces the vtable with a switch to dispatch the calls, which is slower but doesn't have the problems of shifting offsets when adding new opcodes
While I recall having read something similar in a BeOS documentation or newsletter, this is actually not the purpose of this mechanism, at least not the main purpose. Consider the following example with a chain of subclasses: BBase <- BDerived <- User. The former two are system classes, the third is a third-party application class. Let's say they have the following vtables:
BBase: { BBase::foo BBase::Perform BBase::reserved0 } BDerived: { BDerived::foo BDerived::Perform BBase::reserved0 } User: { User:foo BDerived::Perform BBase::reserved0 }Now the system implementer (Be, us) decides to add a new virtual method to BBase and also override it in BDerived. This changes the vtables of BBase and BDerived:
BBase: { BBase::foo BBase::Perform BBase::bar } BDerived: { BDerived::foo BDerived::Perform BDerived::bar }However, unless the User class is rebuilt with the new headers, its vtable remains the same. That is, if on a User object the bar() method is invoked, it will actually call BBase::reserved0. That symbol has of course been provided for binary compatibility. But how is it implemented. We can't make a virtual function call to bar(), since we'd end up calling ourselves again. Invoking BBase::bar() non-virtually would skip BDerived::bar(), though.
This is where Perform is used. We invoke Perform(PERFORM_CODE_BAR). Since that had been overridden by BDerived originally, the call ends up in BDerived::Perform(), which in turn calls BDerived::bar() non-virtually.
Perform() would be superfluous (for this purpose) had we (Be) decided to override the reserved0() in BDerived in the first place.
The mechanism can be seen in action e.g. in BView for the layout management related virtual functions.
CU, Ingo