use vtable_gen::cpp_class; cpp_class! { #[derive(Debug, Default)] #[gen_vtable(no_unimpl)] struct FooImpl { virtual(1) fn foo(&self) -> u32, } } impl FooImplVirtuals for FooImpl { extern "C" fn foo(this: &FooImpl) -> u32 { this.foo() + 31 } } // currently, we don't support impls. you can do them manually if needed cpp_class! { #[impl_generic_base([T = FooImpl])] #[derive(Debug, Default)] #[gen_vtable(no_unimpl)] struct Foo: T { a: u32 virtual(1) extern "fastcall" fn foo2(&self, a: u32, b: f32) -> usize, } } impl FooImplVirtuals for Foo_FooImpl { extern "C" fn foo(_this: &FooImpl) -> u32 { 13 } } impl Foo_FooImplVirtuals for Foo_FooImpl { extern "fastcall" fn foo2(this: &Foo_FooImpl, a: u32, b: f32) -> usize { this.base_foo_impl.foo() as usize + a as usize + b as usize } } #[test] fn layout() { assert_eq!( std::mem::size_of::(), std::mem::size_of::() * 2 ); assert_eq!( std::mem::size_of::(), std::mem::size_of::() * 4 ); } #[test] #[should_panic] fn unimpl_method() { let b = Foo_FooImpl::default(); // ensure that unimplemented methods panic (unsafe { &*(b.base_foo_impl.vfptr as *const FooImplVTable) }.unimpl_0)() } #[test] fn default() { let b = Foo_FooImpl::default(); // manually select the implementation assert_eq!(::foo(&b), 13); assert_eq!(::foo2(&b, 1, 2.0), 16); // call through the vtable assert_eq!(b.foo(), 13); assert_eq!(b.foo2(1, 2.0), 16); }