so true

心怀未来,开创未来!
随笔 - 160, 文章 - 0, 评论 - 40, 引用 - 0
数据加载中……

some notes on linking with shared library

==> Object.h <==
#include <stdio.h>

class Object {
public:
    Object();
#ifdef TEST
    void NoneVirtualFunc() {
        printf("%s, size of class:%lu\n", __PRETTY_FUNCTION__, sizeof(Object));
    }
#endif

#ifdef TEST
    virtual void Func2();
    virtual void Func1();
#else
    virtual void Func1();
    virtual void Func2();
#endif
    virtual void Access();

#ifdef TEST
    void SetOther(int other) {
        m_other = other;
    }
    virtual void Other() {
        printf("%s\n", __PRETTY_FUNCTION__);
    }
#endif

private:
    int m_i1;
#ifdef TEST
    int m_other;
#endif
    int m_i2;
};

==> Object.cpp <==
#include "Object.h"

Object::Object(): m_i1(1), m_i2(2) {
    printf("%s, constructor init, i1:%d, i2:%d\n", __PRETTY_FUNCTION__, m_i1, m_i2);
}

void Object::Func1() {
    printf("%s\n", __PRETTY_FUNCTION__);
}

void Object::Func2() {
    printf("%s\n", __PRETTY_FUNCTION__);
}

void Object::Access() {
    printf("%s, size of class:%lu, i1:%d, i2:%d\n", __PRETTY_FUNCTION__, sizeof(Object), m_i1, m_i2);
}

==> test.cpp <==
#include "Object.h"

//for more details about vtable, see: http://blog.csdn.net/haoel/article/details/1948051

int main(int argc, char* argv[]) {
    Object* obj = new Object();

    obj->Func1();
    obj->Func2();
#ifdef TEST
    obj->SetOther(1000);
#endif
    obj->Access();

#ifdef TEST
    obj->NoneVirtualFunc();
    obj->Other(); //segmentation fault
#endif

    return 0;
}


==> Makefile <==
all:
    @g++ -g -fPIC -o Object.o -fno-rtti -c Object.cpp
    @g++ -shared -o libObject.so Object.o
    @g++ -g -Wall test.cpp -o test -L. -lObject -Wl,-rpath=.
    @./test
    @rm -f test *.o *.so core*


test:
    @g++ -g -fPIC -o Object.o -fno-rtti -c Object.cpp
    @g++ -shared -o libObject.so Object.o
    @g++ -g -Wall test.cpp -o test -L. -lObject -Wl,-rpath=. -DTEST
    @./test
    @rm -f test *.o *.so core*

==> RESULT <==
$ make
Object::Object(), constructor init, i1:1, i2:2
virtual void Object::Func1()
virtual void Object::Func2()
virtual void Object::Access(), size of class:16, i1:1, i2:2

$ make test
Object::Object(), constructor init, i1:1, i2:2
virtual void Object::Func2()
virtual void Object::Func1()
virtual void Object::Access(), size of class:16, i1:1, i2:1000
void Object::NoneVirtualFunc(), size of class:24
make: *** [test] Segmentation fault (core dumped)
make: *** Deleting file `test'

==> KNOWLEDGE <==
一个类一旦已经编译成so了,那么虚函数以及成员变量就都确定了,也就是影响一个类的内存映像的东西都是确定的了。
所以,修改头文件时需要遵循以下原则:
1。可以随意添加非虚函数;
2。不要修改虚函数的相对位置,更不要添加新的虚函数;
3。最好不要添加新的成员变量,如果添加也要在所有成员变量的后面添加,不过如果你不清楚so里的用法的话,很有可能出问题;

其实,说到本质上,就是要心里很清楚,修改前和修改后,该类的内存映像到底是怎样的,固化在so里的代码是不会再变化了;
有兴趣的,可以debug看下虚函数表里指针的情况;如果不用-fno-rtti参数,那么vtable里会多出两项用于typeinfo相关的内容;
增加了新的虚函数后,通过nm -C test | grep Object可以看到,生成的可执行程序里是不会有Other这个虚函数的:
00000000004008f8 W Object::NoneVirtualFunc()
0000000000400920 W Object::SetOther(int)
                 U Object::Object()
0000000000400a60 r Object::NoneVirtualFunc()::__PRETTY_FUNCTION__

而且新加的函数都是W类型,下面通过另一个例子来验证W类型:
==> Object.h <==
#include <stdio.h>

class Object {
public:
    void func() {
        printf("It's the implementation of %s in header file\n", __PRETTY_FUNCTION__);
    }
};

==> test.cpp <==
#include <stdio.h>
#include "Object.h"

int main(int argc, char* argv[]) {
    Object obj;
    obj.func();
    return 0;
}

==> RESULT <==
$ g++ -o test test.cpp
$ ./test
It's the implementation of void Object::func() in header file

==> Object.cpp <==
#include <stdio.h>
class Object {
public:
    void func();
};

void Object::func() {
    printf("%s\n", __PRETTY_FUNCTION__);
}

==> RESULT <==
$ g++ -c -o Object.o Object.cpp
$ g++ -o test test.cpp Object.o
$ ./test
void Object::func()

posted on 2015-03-12 20:50 so true 阅读(266) 评论(0)  编辑  收藏 所属分类: C&C++


只有注册用户登录后才能发表评论。


网站导航: