4

我在运行时加载的共享库中实例化的对象上使用 dynamic_cast 时遇到了一个问题,但前提是该类包含覆盖另一个方法的方法。

我将 Xcode 4.3 与“Apple LLVM 3.1 编译器”一起使用我已经在 linux 上使用 gcc 和 clang 编译了相同的代码并且没有问题,所以我假设它是 Xcode 中的编译器错误,但有人看过这个前?

假设在名为“test3.h”的头文件中定义类

#pragma once

class c1
{
public:
 virtual ~c1 ();
 virtual void foo ();
};

class c2 : public c1
{
public:
 void foo () override;
};

class c3 : public c1
{
public:
};

假设在名为“test3.cpp”的源文件中的静态库中的实现代码

#include "test3.h"

c1::~c1 ()
{
}

void c1::foo ()
{
}

void c2::foo ()
{
}

假设在名为 test2.cpp 的源文件中有一个简单的动态库

#include "test3.h"

extern "C"
c1 * get1 ()
{
 return new c2;
}

extern "C"
c1 * get2 ()
{
 return new c3;
}

假设在名为 test1.cpp 的源文件中有一个简单的可执行应用程序

#include "test3.h"
#include <dlfcn.h>
#include <iostream>

int main ()
{
 auto lib (dlopen ("libtest2.dylib", RTLD_NOW | RTLD_GLOBAL));
 auto a1 (dlsym (lib, "get1"));
 auto a2 (dlsym (lib, "get2"));
 auto f1 ((c1 * (*) ())a1);
 auto f2 ((c1 * (*) ())a2);
 auto o1 (f1 ());
 auto o2 (f2 ());
 auto d1 (dynamic_cast <c2 *> (o1));
 auto d2 (dynamic_cast <c3 *> (o2));
 auto result1 (d1 != 0);
 auto result2 (d2 != 0);
 std::cout << result1 << std::endl;
 std::cout << result2 << std::endl;
}

运行测试程序时,result1 为假,而 result2 为真。我期望 result1 和 result2 都是真的。

有没有人看到这个或可以想到一个解决方法?

4

2 回答 2

0

我认为这个问题的原因是双重的。首先,动态转换在 RTTI 对象上使用相等比较。其次,有两个:一个在主线,一个在动态库。

此问题的解决方法应该是确保要共享的类位于单独的动态链接库中,并且由您的主线和所有其他共享库链接到。

确实它是库/编译器中的一个错误:它不应该使用指针相等来进行动态类型比较。


哎呀。我试过了,但它并没有解决我的问题(g++ 也曾经把它搞砸了)。奇怪的是,我在不同的库中正确地捕获了异常,重新抛出它,通过基类指针正确地捕获它,但是 dynamic_cast 失败了。所以我的建议似乎不起作用(在 OSX 上)。对不起。

于 2012-09-01T05:30:28.310 回答
0

如果您打算将它们从 a 传递.dylib到另一个应用程序,则不能将静态库用于 c++ 类的实现代码 - 您必须使用共享对象。

原因是在链接时,您最终会在 和 中获得类型信息的私有libtest2.dylib副本test1;他们将彼此不兼容。

如果你想让它工作,你需要从链接到应用程序test3.cpp/h的 a中导出类。.dyliblibtest2.dylibtest1

示例Makefile

CXX=clang
CXXFLAGS=-std=c++11

all: libshlib.dylib libtest2.dylib test1

clean:
    rm -f *.o test1 *.dylib

test3.o: test3.cpp test3.h
    $(CXX) $(CXXFLAGS) -c -fPIC test3.cpp -o test3.o

libshlib.dylib: test3.o
    $(CXX) $(CXXFLAGS) -fPIC -shared test3.o -o $@ -lstdc++

test2.o: test2.cpp test3.h
    $(CXX) $(CXXFLAGS) -c -fPIC test2.cpp -o test2.o

libtest2.dylib: libshlib.dylib test2.o
    $(CXX) $(CXXFLAGS) -o $@ -shared test2.o -lstdc++ -L. -lshlib

test1: test1.o test3.h
    $(CXX) $(CXXFLAGS) -o $@ test1.o -lstdc++ -L. -lshlib

test1.o: test1.cpp test3.h
    $(CXX) $(CXXFLAGS) -c -o $@ test1.cpp
于 2012-09-01T15:43:27.430 回答