Object type preservation¶
Having an inheritance tree makes it possible to keep a subtype object as a base type object. If we construct base type object in the target bindings, we will lose the information about object’s actual type. To deal with this problem, CppBind does object type preservation when constructing an object of the user-defined type. After that, saved type information is used to recover the original object in C bindings and construct the object in target language bindings with the correct type.
To implement this feature, CppBind keeps track of the descendant classes/structs for each class/struct. We pass the object’s actual type information from C bindings to target language binding, where the object construction process is done. CppBind allows the user to define the list of descendants via the descendants variable for each class, otherwise using the deduced one. In the target language bindings, the object construction with the actual type is done with switch-case blocks where we compare preserved type information with the possible descendant subtypes.
Here is an example of a base class with a user-defined list of descendant classes:
/**
* An example interface which descendant types are templates. Used for an example of downcast in target language.
* __API__
* action: gen_interface
* package: templates
* descendants:
* - cppbind::example::Stack<cppbind::example::Project>
* - cppbind::example::Stack<cppbind::example::Task>
* - cppbind::example::Stack<cppbind::example::Number<int>>
*/
class Container {
public:
virtual ~Container() = default;
};
Implementation part of above-described process in target language bindings (the main logic is inside "cppbindConstructObject" method)
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 05/12/2022-10:29.
* Please do not change it manually.
*/
package com.examples.templates
import com.examples.cppbind.alias.*
import com.examples.cppbind.exceptionUtils.*
import com.examples.cppbind.exception_helpers.*
import com.examples.getters.NumberInt
import com.examples.simple.Project
import com.examples.simple.Task
/**
* An example interface which descendant types are templates. Used for an example of downcast in target language.
*/
interface IContainer : AutoCloseable {
val id: Long
fun keepCppBindReference(ref: Any)
companion object {
public fun cppbindConstructObject(id: Long, owner: Boolean = false): IContainer {
val idType = jGettypebyid(id)
when (idType) {
StackPrj.cppbindCxxTypeName -> return StackPrj(CppBindObject(id, owner))
StackTask.cppbindCxxTypeName -> return StackTask(CppBindObject(id, owner))
StackNumInt.cppbindCxxTypeName -> return StackNumInt(CppBindObject(id, owner))
else -> return ContainerImpl(CppBindObject(id, owner))
}
}
}
}
open class ContainerImpl
internal constructor(obj : CppBindObject) : IContainer {
companion object {
init {
System.loadLibrary("wrapper_jni")
}
const val cppbindCxxTypeName: String = "cppbind::example::Container"
}
protected var cppbindObj = obj
private var refs: MutableList<Any> = mutableListOf()
override fun keepCppBindReference(ref: Any) {
refs.add(ref)
}
override val id: Long
get() {
if (cppbindObj.id == 0L) {
throw RuntimeException("Object is not allocated")
}
return cppbindObj.id
}
override fun close() {
if (cppbindObj.owner && cppbindObj.id != 0L) {
jFinalize(cppbindObj.id)
cppbindObj.id = 0L
}
}
/**
* Finalize and deletes the object
*/
protected fun finalize() {
close()
}
///// External wrapper functions ////////////
private external fun jFinalize(id: Long): Unit
}
/**
* An example of usage for a type which descendants are template types.
* Used for an example of downcast in target language.
*/
open class ContainerHolder
internal constructor(obj: CppBindObject) : AutoCloseable {
companion object {
init {
System.loadLibrary("wrapper_jni")
}
protected fun construct_helper(container: IContainer): Long {
val kotlintojdkcontainer = container.id
val id = jConstructor(kotlintojdkcontainer)
return id
}
@JvmStatic
private external fun jConstructor(container: Long): Long
const val cppbindCxxTypeName: String = "cppbind::example::ContainerHolder"
}
protected var cppbindObj = obj
private var refs: MutableList<Any> = mutableListOf()
fun keepCppBindReference(ref: Any) {
refs.add(ref)
}
open val id: Long
get() {
if (cppbindObj.id == 0L) {
throw RuntimeException("Object is not allocated")
}
return cppbindObj.id
}
constructor(container: IContainer): this(CppBindObject(construct_helper(container), true)) {
}
val container: IContainer
get() {
val result = jContainer(id)
val jdktokotlinresult : IContainer
jdktokotlinresult = IContainer.cppbindConstructObject(result)
jdktokotlinresult.keepCppBindReference(this)
return jdktokotlinresult
}
override fun close() {
if (cppbindObj.owner && cppbindObj.id != 0L) {
jFinalize(cppbindObj.id)
cppbindObj.id = 0L
}
}
/**
* Finalize and deletes the object
*/
protected fun finalize() {
close()
}
///// External wrapper functions ////////////
private external fun jContainer(id: Long): Long
private external fun jFinalize(id: Long): Unit
}
private external fun jGettypebyid(id: Long): String
Note
Object type preservation process for Python is done by pybind.
/**
* ______ .______ .______ .______ __ .__ __. _______
* / || _ \ | _ \ | _ \ | | | \ | | | \
* | ,----'| |_) | | |_) | | |_) | | | | \| | | .--. |
* | | | ___/ | ___/ | _ < | | | . ` | | | | |
* | `----.| | | | | |_) | | | | |\ | | '--' |
* \______|| _| | _| |______/ |__| |__| \__| |_______/
*
* This file is generated by cppbind on 05/12/2022-10:26.
* Please do not change it manually.
*/
import CWrapper
import Foundation
/**
* An example interface which descendant types are templates. Used for an example of downcast in target language.
*/
public protocol Container {
var cself: CppBindCObject { get }
func keepCppBindReference(_ object: Any)
}
extension Container {
}
public class ContainerImpl: Container {
public let cself: CppBindCObject
public let owner: Bool
private var refs: [Any]
// internal main initializer
internal required init(_ _cself: CppBindCObject, _ _owner: Bool = false) {
self.cself = _cself
self.owner = _owner
self.refs = []
}
deinit {
release_CppbindExample_ContainerImpl(cself, owner)
}
public func keepCppBindReference(_ object: Any) {
self.refs.append(object)
}
class var cppbindCxxTypeName : String { return "cppbind::example::Container" }
class func cppbindConstructObject(_ cppbindObj: CppBindCObject, _ owner: Bool = false) -> Container {
let typeName = String(cString: cppbindObj.type)
switch(typeName) {
case(StackPrj.cppbindCxxTypeName):
return StackPrj(cppbindObj, owner)
case(StackTask.cppbindCxxTypeName):
return StackTask(cppbindObj, owner)
case(StackNumInt.cppbindCxxTypeName):
return StackNumInt(cppbindObj, owner)
default:
return ContainerImpl(cppbindObj, owner)
}
}
}
/**
* An example of usage for a type which descendants are template types.
* Used for an example of downcast in target language.
*/
public class ContainerHolder {
public let cself: CppBindCObject
public let owner: Bool
private var refs: [Any]
/// internal main initializer
internal required init(_ _cself: CppBindCObject, _ _owner: Bool = false) {
self.cself = _cself
self.owner = _owner
self.refs = []
}
deinit {
release_CppbindExample_ContainerHolder(cself, owner)
}
public func keepCppBindReference(_ object: Any) {
self.refs.append(object)
}
public convenience init(container: Container) {
let swifttosccontainer = container.cself
var cppbindErr = CppBindCObject()
self.init(create_CppbindExample_ContainerHolder(swifttosccontainer, &cppbindErr), true)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
}
public var container: Container {
var cppbindErr = CppBindCObject()
let result = _prop_get_CppbindExample_ContainerHolder_container(cself, &cppbindErr)
if cppbindErr.type != nil {
let errorType = String(cString: cppbindErr.type!)
switch errorType {
case ("std::exception"):
let excObj = StdException(cppbindErr, true)
ExceptionHandler.handleUncaughtException(excObj.what())
default:
cppbindErr.type.deallocate()
ExceptionHandler.handleUncaughtException("Uncaught Exception")
}
}
var sctoswiftresult: Container
sctoswiftresult = ContainerImpl.cppbindConstructObject(result)
sctoswiftresult.keepCppBindReference(self)
return sctoswiftresult
}
class var cppbindCxxTypeName : String { return "cppbind::example::ContainerHolder" }
}