0

Using Qt (5.12, with r18b, clang), I create a shared library exporting some classes. Then I create a program doing some dynamic_cast between those classes. Under Windows with VS 2015, it works perfectly (with __declspec not posted below). Under Android with clang, dynamic_cast fails. I could read lots of topics like:

dynamic_cast an interface from a shared library which was loaded by lt_dlopen(libtool) doesn't work

So I tried to add some flags to my library project, tried many things (not sure which one is upposed to work):

QMAKE_LFLAGS += -Wl,--export-dynamic
QMAKE_LFLAGS += -Wl,-E
QMAKE_LFLAGS += -Bsymbolic

However, even if I see those flags are used upon link, it still fails.

Here is my MCVE:

dynamiccast_lib.pro:

TARGET = dynamiccast_lib

QT -= core
QT -= gui

QMAKE_LFLAGS += -Wl,--export-dynamic
QMAKE_LFLAGS += -Wl,-E
QMAKE_LFLAGS += -Bsymbolic

TEMPLATE = lib

CONFIG += shared

SOURCES +=  \ 
C:/dev/vobs_sde/public/lib/dynamiccast_lib/src/dynamiccast_lib.cpp

HEADERS +=  \ 
C:/dev/vobs_sde/public/lib/dynamiccast_lib/ifc/dynamiccast_lib.h

INCLUDEPATH +=  \ 
C:/dev/vobs_sde/public/lib/dynamiccast_lib/ifc

dynamiccast_prg.pro:

TARGET = dynamiccast_prg

QT -= core
QT -= gui

QMAKE_LFLAGS += -Wl,--export-dynamic
QMAKE_LFLAGS += -Wl,-E
QMAKE_LFLAGS += -Bsymbolic

TEMPLATE = app

SOURCES +=  \ 
C:/dev/vobs_sde/public/prg/dynamiccast_prg/src/main.cpp

INCLUDEPATH +=  \ 
C:/dev/vobs_sde/public/prg/dynamiccast_prg/inc \
C:/dev/vobs_sde/public/lib/dynamiccast_lib/ifc

LIBS += -l$$OUT_PWD/../../lib/dynamiccast_lib/libdynamiccast_lib.so
PRE_TARGETDEPS += $$OUT_PWD/../../lib/dynamiccast_lib/libdynamiccast_lib.so

dynamiccast_lib.h:

#pragma once

#include <iostream>

class BaseClass
{
public:
    BaseClass()
    {
    }

    virtual void show() = 0;
};

class DerivedClass : public BaseClass
{
public:
    DerivedClass( int attr ) : attr( attr )
    {
    }

    void show() override
    {
        std::cout << attr << std::endl;
    }

private:
    int attr;
};

class DYNAMICCAST_LIB_API Helper
{
public:
    static BaseClass* CreateIntObject( int attr );
};

dynamiccast_lib.cpp:

#include "dynamiccast_lib.h"

BaseClass* Helper::CreateIntObject( int attr )
{
    return new DerivedClass( attr );
}

main.cpp:

#include "dynamiccast_lib.h"
#include <iostream>

int main( int argc, char* argv[] )
{
    BaseClass* ptr = Helper::CreateIntObject(3);
    DerivedClass* casted = dynamic_cast< DerivedClass* >( ptr );
    casted->show();    
    return 0;
}

This code crashs because casted is NULL. How can I make this simple code work under Android?

jpo38
  • 20,821
  • 10
  • 70
  • 151

1 Answers1

0

After some investigation, I could fix this issue myself. There is no need to add any link flag at all. I could get this fix (have dynamic_cast work) simply by adding a virtual method in BaseClass and implementing it in dynamiccast_lib.cpp.

Added in dynamiccast_lib.h:

virtual ~BaseClass;

Added in dynamiccast_lib.cpp:

BaseClass::~BaseClass
{
}

This makes dynamic_cast work just right from the program. Any virtual function will fix this (not only destructor), but the implementation MUST be in the source file, not in the header file (otherwise dynamic_cast still fails). That's surprising, but that's what I observed by testing.

jpo38
  • 20,821
  • 10
  • 70
  • 151
  • The reason is likely because on windows, dynamic_cast does a string comparison for the name of the class. In contrast on other platforms, RTTI or vtable pointers may be compared directly (and two classes named Foo in two different DLLs may end up having different RTTI pointers, one per dll / executable) – Jean-Michaël Celerier May 29 '21 at 12:37