如何在运行时加载C++函数和类

Problem

有些时候你想在运行时加载一个lib或者function or class,这种事情经常发生在你开发一个plugin或者module时遇到。

在C语言里,你可以轻松的利用dlopen, dlsym, dlclose来做到,但是在C++的世界里却没那么简单了。困难就在C++语言的name mangling上,还有一部分就是dlopen函数是用纯C语言写的,不提供load classes功能。

在解析如何load function和class在c++语言中之前,还是线弄清问题吧---name mangling。

C++ Name Mangling

在C++程序里(或lib or object file中),所有的non-static functions都是以二进制文件symbols来表示。这些symbols都是些特殊的文本字符串,都是唯一的在程序中,lib中活着object file中来标示一个文件。

然而在C语言中,函数的symbol名字就是函数名字本身,例如strcpy的symbol就是strcpy,所以在C语言中不会有中non-static函数出现重名情况。

由于C++有很多C语言没有的功能,例如class,函数的overloading,异常处理等等,所以symbol不可能简单的以函数名来定。为了解决这个问题,C++提出了name mangling,这个name mangling的功能就是把function的名字转换成只有compiler知道的奇怪字符串,利用该函数所有的已知信息,如果函数参数的类型,个数,函数等等,所有如果函数名字为foo(int, char),利用name mangling之后,其名字可能是foo_int_char或者其他字符串也说不定。

现在的问题是在C++标准里(ISO14882)中还没有定义这个function name是被怎样的mangled的,每个编译器都有自己的一套方法。

Classes

另外一个问题就是dlopen函数仅支持load 函数,不支持load class。

很明显的是如果你想使用该class,就需要new instance出来。

Solution

extern “C”

C++有个特殊的关键字来声明函数用C的方式来绑定——extern “C”,在C++中函数如果用extern “C”在前面声明的话,就表示该函数的symbol以C语言方式来命名。

所以只有非成员函数可以用extern “C”来声明,而且他们不能被重载。 
虽然很局限,但是这样足够利用dlopen来运行时调用function了。需要强调的是用extern “C”不是就不可以在function内写C++ 代码,依然可以调用class和class的function的。

Loading functions

用dlsym,加载C++函数就像加载C函数一样,你要加载的函数必须要用extern “C”来声明,避免name mangling。 
Example 1: load a function

<code class="language-c++ hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <iostream></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <dlfcn.h></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main() {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span>;
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C++ dlopen demo\n\n"</span>;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// open the library</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Opening hello.so...\n"</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>* handle = dlopen(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"./hello.so"</span>, RTLD_LAZY);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!handle) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cannot open library: "</span> << dlerror() << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
}
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// load the symbol</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Loading symbol hello...\n"</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typedef</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (*hello_t)();
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// reset errors</span>
    dlerror();
    hello_t hello = (hello_t) dlsym(handle, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"hello"</span>);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *dlsym_error = dlerror();
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dlsym_error) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cannot load symbol 'hello': "</span> << dlsym_error <<
            <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>;
        dlclose(handle);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// use it to do the calculation</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Calling hello...\n"</span>;
    hello();
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// close the library</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Closing library...\n"</span>;
    dlclose(handle);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li></ul>

hello.cpp

<code class="language-c++ hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <iostream></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> hello() {
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"hello"</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

注意,以下两种方式是等价的

<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> foo
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> bar();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

<code class="language-c hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C"</span> {
   <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> foo;
   <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> bar();
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

但是定义变量却是不等价的

load classes

加载类比加载函数还是有点困难的。

我们不能通过new instance来实例一个class在执行的时候,因为某些时候我们根本不知道要记载的类的名字,

怎么解决呐?我们可以通过多态性来解决。开始我们定义一个base interface,声明一些抽象方法,子类继承并实现这些方法。

所以现在我们需要定义两个helper 函数,用extern “c”声明,一个用来new一个class实例,返回class的指针,一个用来销毁这个指针。

基于此,我们就可以用dlsym来调用这两个helper函数了。

Example 2: loading class 
main.cpp

<code class="language-c++ hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "polygon.hpp"</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <iostream></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <dlfcn.h></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main() {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span>;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// load the triangle library</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>* triangle = dlopen(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"./triangle.so"</span>, RTLD_LAZY);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!triangle) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cannot load library: "</span> << dlerror() << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// reset errors</span>
    dlerror();
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// load the symbols</span>
    create_t* create_triangle = (create_t*) dlsym(triangle, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"create"</span>);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* dlsym_error = dlerror();
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dlsym_error) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cannot load symbol create: "</span> << dlsym_error << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
}
    destroy_t* destroy_triangle = (destroy_t*) dlsym(triangle, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"destroy"</span>);
    dlsym_error = dlerror();
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dlsym_error) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cerr</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cannot load symbol destroy: "</span> << dlsym_error << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// create an instance of the class</span>
    polygon* poly = create_triangle();
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// use the class</span>
    poly−>set_side_length(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>);
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">cout</span> << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"The area is: "</span> << poly−>area() << <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\n'</span>;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// destroy the class</span>
    destroy_triangle(poly);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// unload the triangle library</span>
    dlclose(triangle);
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li></ul>

polygon.hpp

<code class="language-c++ hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#ifndef POLYGON_HPP</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">define</span> POLYGON_HPP</span>
class polygon {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> side_length_;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-title" style="box-sizing: border-box;">polygon</span>()
        : <span class="hljs-title" style="box-sizing: border-box;">side_length_</span>(0) {}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> ~polygon() {}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> set_side_length(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> side_length) {
        side_length_ = side_length;
}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> area() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
};
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// the types of the class factories</span>
typedef polygon* create_t();
typedef <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> destroy_t(polygon*);
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#<span class="hljs-keyword" style="box-sizing: border-box;">endif</span></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

triangle.cpp:

<code class="language-c++ hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include "polygon.hpp"</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <cmath></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> triangle : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> polygon {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">double</span> area() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> side_length_ * side_length_ * <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sqrt</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>) / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
        } };
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// the class factories</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C"</span> polygon* create() {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> triangle;
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extern</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"C"</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> destroy(polygon* p) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> p;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

这里还有一些需要提醒的地方:

  • 你必须提供一个creation和destruction函数,因为在C中,你是无法在执行时调用delete来销毁对象的。
  • interface class 中的析构函数应该定义为virtual的,这种做法可能在不必要的地方很少见,但是也不能因为这个而冒险不是。

上面的例子笔者已经测试通过了,完全OK。

想研究更深的,可以查看以下论文:

  1. A lightweight mechanism to update code in a running program Dynamic c++ classes
  2. Dynamic c++ classes A lightweight mechanism to update code in a running program
  3. (Dynamic Code Updates)[http://ttic.uchicago.edu/~mmaire/papers/pdf/dynamic_update.pdf]

参考:C++ dlopen mini HOWTO

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值