前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实战C++对象模型之成员函数调用

实战C++对象模型之成员函数调用

作者头像
一见
发布2019-03-20 15:03:12
1K0
发布2019-03-20 15:03:12
举报
文章被收录于专栏:蓝天

先说结论:C++的类成员函数和C函数实质是一样的,只是C++类成员函数多了隐藏参数this。

通过本文的演示,可以看见这背后的一切,完全可C函数方式调用C++类普通成员函数和C++类虚拟成员函数。

为了实现C函数方式调用C++类成员函数,准备两个文件:。

1) 被调用的C++类成员函数源代码文件aaa.cpp

代码语言:javascript
复制
#include  // fprintf
class X
{
public:
void xxx();
private:
int m;
int n;
};
void X::xxx() // bbb.cpp完全以C函数方式调用类X的成员函数xxx
{
printf("m=%d, n=%d\n", m, n);
}

把aaa.cpp编译成共享库:

代码语言:javascript
复制
$ g++ -g -o libaaa.so aaa.cpp -fPIC -shared

2) 调用的C++类成员函数源代码文件bbb.cpp

代码语言:javascript
复制
#include  // dlopen
#include  // basename
#include  // fprintf
#include  // exit
#include  // strdup
struct X // 对应于aaa.cpp中类X
{
int m;
int n;
};
// 定义C风格函数指针XXX,使用前让它指向类X的成员函数xxx
typedef void (*XXX)(struct X*); // 参数实为aaa.cpp中类X的this指针
// 需要指定一个命令行参数argv[1],
// 值为aaa.cpp中类X的成员函数xxx的名字,
// 因为C++编译器会对类X的成员函数xxx名字编码,所以实际名字不会是xxx,
// 本文测试环境xxx编码后的名为_ZN1X3xxxEv,
// 不同环境可能有区别,特别是不同编译器通常不同,因为C++标准未对这个做规范。
int main(int argc, char* argv[])
{
char* prog = strdup(argv[0]);
if (argc != 2) {
fprintf(stderr, "Usage: %s symbol-name\n", basename(prog));
exit(1);
}
// 为测试方便,两个文件放在同一目录下,省去设置LD_LIBRARY_PATH
const char* so = "./libaaa.so";
void* h = dlopen(so, RTLD_NOW); // 加载类X所在共享库文件
if (NULL == h) {
fprintf(stderr, "dlopen %s failed: %s\n", so, dlerror());
exit(1);
}
XXX xxx = (XXX)dlsym(h, argv[1]); // 取和类X的类成员函数xxx的函数地址,以便可以调用它
if (NULL == xxx) {
fprintf(stderr, "dlsym %s failed: %s\n", argv[1], dlerror());
exit(1);
}
// 第1组测试数据
struct X x1;
x1.m = 19;
x1.n = 18;
(*xxx)(&x1); // 这里完全以C函数方式调用类X的类成员函数xxx
// 第2组测试数据
struct X x2;
x2.m = 2019;
x2.n = 2018;
(*xxx)(&x2); // 这里完全以C函数方式调用类X的类成员函数xxx
// 第3组测试数据
x2.m = 29;
x2.n = 28;
(*xxx)(&x2); // 这里完全以C函数方式调用类X的类成员函数xxx
return 0;
}

把bbb.cpp编译成可执行程序:

代码语言:javascript
复制
$ g++ -g -o bbb bbb.cpp -ldl

执行bbb,看看效果,运行结果和预计完全一致:

代码语言:javascript
复制
$ ./bbb _ZN1X3xxxEv
m=19, n=18
m=2019, n=2018
m=29, n=28

以更优雅方式运行:

代码语言:javascript
复制
$ ./bbb `nm libaaa.so | awk /xxx/'{print $3}'`
m=19, n=18
m=2019, n=2018
m=29, n=28

对于类虚拟成员函数,做法是一样的,只是bbb.cpp中的struct X定义得改一下,因为有虚拟函数的类的头一个指针大小为指向虚拟函数表的指针。

包含虚拟函数的aaa.cpp:

代码语言:javascript
复制
#include  // fprintf
class X
{
public:
virtual void xxx(); // 编码后的函数名和是否为虚拟函数无关
private:
int m;
int n;
};
void X::xxx() // bbb.cpp完全以C函数方式调用类X的成员函数xxx
{
printf("m=%d, n=%d\n", m, n);
}

bbb.cpp只需修改struct X的定义:

代码语言:javascript
复制
struct X // 对应于aaa.cpp中类X
{
void* p; // 对应aaa.cpp中类X的虚拟函数表指针
int m;
int n;
};

其它操作步骤完全相同,运行同样可得到预期的结果。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/03/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档