You're going to need a wrapper to call that virtual destructor. You just are. Angelscript can't know to look in a vtable just from a function pointer. However, you can mitigate that by using templates!
I've actually got a fairly complete set of templated wrappers that I use. I just use these by default, instead of messing around with asMETHODPR. It really saves me a lot of headache, as it allows the compiler to figure out the exact name and parameters to the function for me, whether it be implemented as a member or a free function or whatever.
/*Angelscript Class Binding Utility TemplatesCopyright (c) 2006 Anthony CasteelThis software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you usethis software in a product, an acknowledgment in the product documentation would be appreciated but is not required.2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.3. This notice may not be removed or altered from any source distribution.Anthony Casteeljm@omnisu.com*//* Important Notes --Motivation --Binding operators to angelscript is HARD. If there are overloads involved, you have to specify exactly which overload you meanusing complicated macros that the preprocessor often chokes on.For example, try binding operator[]. The preprocessor often failswhen it encounters that [] construct in the name of the function.These templates solve that problem by invoking C++ overloadresolution system. These templates wrap the operator and makeunqualified calls to the operator, allowing the compiler to choosethe best match using argument dependant lookup and overloadresolution. All variable types are templated for maximum flexibility.The templates do not enforce proper reference usage; you mustexplicitly add & to your template parameters. No quarantees aremade as to how well this will work if you don't use cannonicaloperator signatures.AngelScript requires that some operators - such as += - be bound asmembers. C++ makes no such restriction. In the case where operator+=is declared globally, as T& operator+=(T& lhs, const T& rhs), thereis no way to directly bind it to AngelScript, as AngelScript requiresthis operator to be bound with either the asCALL_THISCALL orasCALL_CDECL_OBJLAST convention. A wrapper is neccessary in thiscase. These templates can also be used to automate the generationof such a wrapper.If your class is not const correct, these templates will not work. Notice that the wrappers do NOT take anything by reference. If a parametershould be passed by reference, include the reference in the type when instantiating the template. This decision was made because, by default, AngelScript cannot use C++ references directly. To use references properly,you must either use AutoHandles or turn on asUNSAFE_REFERENCES.The constructors-with-arguments wrappers take up to only 5 arguments.This is easily extendable.Naming Conventions --When a return value is appropriate, it's type is first.Constructors take the class first, followed by the parameters.Binary operators take the return type, the first parameter, and thesecond, in that order.Binary Operator: R operater???(F lhs, S rhs)Binary Member operators take template parameters in the same order asglobal Binary Operators.Binary Member Operator: R S::operator???(F lhs)Operator-> is experimentally wrapped in MemberSelection. This may or may not work.Some operators not supported --() - Would require something similiar to Construct#, if supported by AS++ - Not supported by AS (Implementations still provided)-- - Not supported by AS (Implementations still provided)* - Not supported by AS& - Don't overload this. ...(type) - Not supported by AS, - Don't overload this.new - AS provides alternate mechanism?new[] - See abovedelete - See abovedelete[]- See above-> - Experimental ImplementationExample Usage --Binding a few operators for the type 'foo'//copy constructorengine->RegisterObjectBehaviour("foo",asBEHAVE_CONSTRUCT,"void f(const foo&)",asFUNCTION((Wrap::Construct1<foo,foo&>)),asCALL_CDECL_OBJLAST);//operator+engine->RegisterGlobalBehaviour(asBEHAVE_ADD,"foo f(const foo&,const foo&)",asFUNCTION((Wrap::Add<foo,foo&,foo&>)),asCALL_CDECL);//operator+=engine->RegisterObjectBehaviour("foo",asBEHAVE_ADD_ASSIGN,"foo& f(const foo&)",asFUNCTION((Wrap::AddAssign<foo&,foo,foo&>)),asCALL_CDECL_OBJLAST);*/#ifndef JM_CLASS_BINDING_UTILITY_TEMPLATES_H#define JM_CLASS_BINDING_UTILITY_TEMPLATES_Hnamespace Wrap{ //Constructors (with up to 5 parameters) //Use asCALL_CDECL_OBJLAST template<typename T> void Construct(T* ptr) { new (ptr) T(); } //Can also be used as copy constructor template<typename T, typename P1> void Construct1(P1 p1, T* ptr) { new (ptr) T(p1); } template<typename T, typename P1, typename P2> void Construct2(P1 p1, P2 p2, T* ptr) { new (ptr) T(p1,p2); } template<typename T, typename P1, typename P2, typename P3> void Construct3(P1 p1, P2 p2, P3 p3, T* ptr) { new (ptr) T(p1,p2,p3); } template<typename T, typename P1, typename P2, typename P3, typename P4> void Construct4(P1 p1, P2 p2, P3 p3, P4 p4, T* ptr) { new (ptr) T(p1,p2,p3,p4); } template<typename T, typename P1, typename P2, typename P3, typename P4, typename P5> void Construct5(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, T* ptr) { new (ptr) T(p1,p2,p3,p4,p5); } //Bind as type behavior; use asCALL_CDECL_OBJLAST template<typename R,typename F,typename S> R Assign(const S rhs, F* ptr) { return (*ptr) = rhs; } template<typename F> void Destroy(F* ptr) { ptr->~F(); } //Comparison operators. //Bind as global behaviors; use asCALL_CDECL template<typename F,typename S> bool Equal(const F lhs, const S rhs) { return lhs == rhs; } template<typename F,typename S> bool NotEqual(const F lhs, const S rhs) { return lhs != rhs; } template<typename F,typename S> bool GreaterEqual(const F lhs, const S rhs) { return lhs >= rhs; } template<typename F,typename S> bool LessEqual(const F lhs, const S rhs) { return lhs <= rhs; } template<typename F,typename S> bool Greater(const F lhs, const S rhs) { return lhs > rhs; } template<typename F,typename S> bool Less(const F lhs, const S rhs) { return lhs < rhs; } //Unary operators. //Bind as type behavior; use asCALL_CDECL_OBJLAST template<typename R,typename F> R Not(F* thisp) { return !(*thisp); } template<typename R,typename F> R Negate(F* thisp) { return -(*thisp); } template<typename R,typename F> R Positate(F* thisp) { return +(*thisp); } template<typename R,typename F> R BinaryComplement(F* thisp) { return ~(*thisp); } //Binary operators. Operator, Assign variety. //Bind operator as global behavior; use asCALL_CDECL //Bind assign variety as type behavior; use asCALL_CDECL_OBJLAST template<typename R,typename F,typename S> R Add(const F lhs, const S rhs) { return lhs+rhs; } template<typename R,typename F,typename S> R AddAssign(const S rhs, F* thisp) { return (*thisp) += rhs; } template<typename R,typename F,typename S> R Subtract(const F lhs, const S rhs) { return lhs-rhs; } template<typename R,typename F,typename S> R SubtractAssign(const S rhs, F* thisp) { return (*thisp) -= rhs; } template<typename R,typename F,typename S> R Multiply(const F lhs, const S rhs) { return lhs*rhs; } template<typename R,typename F,typename S> R MultiplyAssign(const S rhs, F* thisp) { return (*thisp) *= rhs; } template<typename R,typename F,typename S> R Devide(const F lhs, const S rhs) { return lhs/rhs; } template<typename R,typename F,typename S> R DevideAssign(const S rhs, F* thisp) { return (*thisp) /= rhs; } template<typename R,typename F,typename S> R Modulus(const F lhs, const S rhs) { return lhs%rhs; } template<typename R,typename F,typename S> R ModulusAssign(const S rhs, F* thisp) { return (*thisp) %= rhs; } template<typename R,typename F,typename S> R ShiftLeft(const F lhs, const S rhs) { return lhs << rhs; } template<typename R,typename F,typename S> R ShiftLeftAssign(const S rhs, F* thisp) { return (*thisp) <<= rhs; } template<typename R,typename F,typename S> R ShiftRight(const F lhs, const S rhs) { return lhs >> rhs; } template<typename R,typename F,typename S> R ShiftRightAssign(const S rhs, F* thisp) { return (*thisp) >>= rhs; } template<typename R,typename F,typename S> R BinaryAnd(const F lhs, const S rhs) { return lhs & rhs; } template<typename R,typename F,typename S> R BinaryAndAssign(const S rhs, F* thisp) { return (*thisp) &= rhs; } template<typename R,typename F,typename S> R BinaryOrRight(const F lhs, const S rhs) { return lhs | rhs; } template<typename R,typename F,typename S> R BinaryOrAssign(const S rhs, F* thisp) { return (*thisp) |= rhs; } template<typename R,typename F,typename S> R BinaryXorRight(const F lhs, const S rhs) { return lhs ^ rhs; } template<typename R,typename F,typename S> R BinaryXortAssign(const S rhs, F* thisp) { return (*thisp) ^= rhs; } //These binary operators do not have an assign variety template<typename R,typename F,typename S> R LogicalAndRight(const F lhs, const S rhs) { return lhs && rhs; } template<typename R,typename F,typename S> R LogicalOrRight(const F lhs, const S rhs) { return lhs || rhs; } //Index operator //Bind as type behavior; use asCALL_CDECL_OBJLAST template<typename R,typename F,typename S> R Index(const S i, F* thisp) { return (*thisp); } //Increment operators (Not supported by AngelScript) //Bind as type behavior; use asCALL_CDECL_OBJLAST template<typename R,typename F> R PreIncrement(F* thisp) { return ++(*thisp); } template<typename R,typename F> R PostIncrement(F* thisp) { return (*thisp)++; } template<typename R,typename F> R PreDecrement(F* thisp) { return --(*thisp); } template<typename R,typename F> R PostDecrement(F* thisp) { return (*thisp)--; } //MemberSelection operator - MAY OR MAY NOT WORK. //Bind as type behavior; use asCALL_CDECL_OBJLAST template<typename R,typename F> R MemberSelection(F* thisp) { return thisp->operator->(); } //Method through smart pointer wrapper //Type guide: // R - return type // P - smart pointer type // C - type smart pointer points too // M - method on C // rest - parameters //use asCALL_CDDECL_OBJLAST template<typename R,typename P, typename C, R(C::*M)()> R MethodThroughPointer0(P* thisp) { return ((**thisp).*M)(); } template<typename R,typename P, typename C, R(C::*M)(), typename P1> R MethodThroughPointer1(P1 p1, P* thisp) { return ((**thisp).*M)(p1); } template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2> R MethodThroughPointer2(P1 p1, P2 p2, P* thisp) { return ((**thisp).*M)(p1,p2); } template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2, typename P3> R MethodThroughPointer3(P1 p1, P2 p2, P3 p3, P* thisp) { return ((**thisp).*M)(p1,p2,p3); } template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2, typename P3, typename P4> R MethodThroughPointer4(P1 p1, P2 p2, P3 p3, P4 p4, P* thisp) { return ((**thisp).*M)(p1,p2,p3,p4); } template<typename R,typename P, typename C, R(C::*M)(), typename P1, typename P2, typename P3, typename P4, typename P5> R MethodThroughPointer5(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P* thisp) { return ((**thisp).*M)(p1,p2,p3,p4,p5); }}#endif
This header has fairly good documentation of it's usage and even some examples. I never actually wrote direct method wrappers, as I didn't need them - but, looking at it now, the MethodThroughPointer wrappers should work as well with a raw pointer as a smart pointer.