diff --git a/README.md b/README.md index 979bd82..47b7b20 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,29 @@ auto multi_vector_base = mod.add_type>>("MultiVectorBase") auto vector_base = mod.add_type>>("VectorBase", multi_vector_base.dt()); ``` +### Conversion + +Conversion to the base type happens automatically, or can be forced by calling convert, e.g. + +```julia +convert(A,b) +``` + +Where we have `b::B` and `B <: A` + +For the equivalent of a C++ `dynamic_cast`, we need to use pointers because the conversion may fail, i.e: + +```julia +convert(CxxPtr{B},CxxPtr(a)) +``` + +This is equivalent to the C++ code: +```c++ +dynamic_cast(&a); +``` + +Use `isnull` on the result to check if the conversion was successful or not. + See the test at [`examples/inheritance.cpp`](https://github.com/JuliaInterop/libcxxwrap-julia/tree/master/examples/inheritance.cpp) and [`test/inheritance.jl`](test/inheritance.jl). ## Enum types diff --git a/src/CxxWrap.jl b/src/CxxWrap.jl index c18949d..421bffe 100644 --- a/src/CxxWrap.jl +++ b/src/CxxWrap.jl @@ -294,6 +294,7 @@ Base.setindex!(x::CxxBaseRef, val, i::Int) = Base.setindex!(x[], val, i) Base.unsafe_convert(to_type::Type{<:CxxBaseRef}, x) = to_type(x.cpp_object) # This is defined on the C++ side for each wrapped type +cxxdowncast(::Type{T}, x::CxxPtr{T}) where {T} = x cxxupcast(x) = cxxupcast(CxxRef(x)) cxxupcast(x::CxxRef) = error("No upcast for type $(supertype(typeof(x))). Did you specialize SuperType to enable automatic upcasting?") function cxxupcast(::Type{T}, x) where {T} @@ -301,6 +302,9 @@ function cxxupcast(::Type{T}, x) where {T} end cxxupcast(::Type{T}, x::CxxBaseRef{T}) where {T} = x +# Dynamic cast equivalent +Base.convert(::Type{CxxPtr{DerivedT}}, x::CxxPtr{SuperT}) where {SuperT, DerivedT <: SuperT} = cxxdowncast(DerivedT, x) + struct ConstArray{T,N} <: AbstractArray{T,N} ptr::ConstCxxPtr{T} size::NTuple{N,Int} @@ -582,6 +586,7 @@ map_julia_arg_type(t::Type{ConstCxxPtr{CxxChar}}) = Union{ConstPtrTypes{Cchar}, # names excluded from julia type mapping const __excluded_names = Set([ + :cxxdowncast, :cxxupcast, :__cxxwrap_smartptr_dereference, :__cxxwrap_smartptr_construct_from_other, @@ -808,7 +813,7 @@ function readmodule(so_path_cb::Function, funcname, m::Module, flags) so_path = so_path_cb() fptr = Libdl.dlsym(Libdl.dlopen(so_path, flags), funcname) register_julia_module(m, fptr) - include_dependency(so_path) + include_dependency(Libdl.dlpath(so_path)) end function wrapmodule(so_path::String, funcname, m::Module, flags) diff --git a/test/inheritance.jl b/test/inheritance.jl index f2d2c1a..0eb960a 100644 --- a/test/inheritance.jl +++ b/test/inheritance.jl @@ -40,7 +40,15 @@ global d = D() @test take_ref(d) == "D" # factory function returning an abstract type A -@test message(create_abstract()) == "B" +let abstract_b = create_abstract() + @test message(abstract_b) == "B" + abstract_b_ptr = CxxPtr(abstract_b) + @test !isnull(convert(CxxPtr{B},abstract_b_ptr)) + @test message(convert(CxxPtr{B},abstract_b_ptr)) == "B" + @test isnull(convert(CxxPtr{C},abstract_b_ptr)) + @test isnull(convert(CxxPtr{D},abstract_b_ptr)) + @test convert(CxxPtr{A},abstract_b_ptr) === abstract_b_ptr +end @test dynamic_message_c(c) == "C"