C++能不能支持Java和ObjC的反射?

要回答这个问题。首先我们要清楚什么是反射。什么是反射?

教科书的解释我就不说了,(^o^)事实上我也记不得。实际开发应用的反射就是在没有某个类型的头文件或者类结构定义的情况下,存取这个类型的对象的成员字段的值。调用这个对象的成员函数(方法)。

比方我有定义了一个类型 Class  A,里面有 a,b,c三个字段,有fun()函数。

如今我手里仅仅有一个 void* pA,注意它的类型仅仅是一个void指针,我手里也没有Class的头文件。我要怎么样得到,a,b。c的值呢?怎么调用fun函数呢?另一种需求就是通过字符串运行代码。比方已经拿到了一A的对象pA了,还拿到了一个字符串 "pA->fun()",如今怎么样才干将这个字符串代表的代码。运行了呢?(后面这样的需求最典型的需求就是表达式引擎)。以上说的就是反射的用处和优点,非常多实际需求中使用起来是非常非常方便的,能够在非常多场合节省非常多时间,少写非常多代码。

众所周知。Java和ObjC支持反射。当然还有其它语言也支持,本人知识水平有限。不能全然列举还请见谅。

假设要实现反射,就须要实现例如以下几个功能:

拿到一个对象指针。哪怕它是void。也能通过一些API,得到它的真实类类型名称。比方java能够得到它的实际类型的包路径+类名

拿到这个对象指针,还能得到它全部的成员变量。成员函数的名称,类型(字段),參数和返回类型(函数),以字符串或者其它封装类型返回。核心还是字符串。

拿到这个对象指针,能够通过字符串。运行某个函数。能够通过字符串,取得某个成员的值。

Java和ObjC都能支持反射,另一个前提是由于他们都统一基类。比方java里叫 java.lang.Object 。ObjC里面是 NSObject。有了统一基类,才可以预先定义一套反射的机制和API。不论什么继承这个基类的实现类,都附带赠送了早已实现的反射功能。

而C++没有标准基类,各种框架,各种平台有各种各样的框架,类库。

如果我们自己在实际开发的系统里面,定义一个统一基类,是不是能在C++里面。实现反射功能,哪怕是别扭的实现也好啊,这样也能够降低非常多苦逼C++开发者的工作量的呀,多好的事啊。

试试吧

首先我们如果应用程序里面的全部类。都有一个公共基类。

其次C++里面的成员变量,成员函数,对象,全部一切,都是指针定位。

所以我们先要解决,通过“一个对象指针 + 一个函数指针调用函数的问题”。

完整演示程序已经写好了

#include "stdafx.h"

class CXObject
{
public:
int doSum(int a, int b);
}; typedef int (CXObject::*pf_doSum)(int, int); int CXObject::doSum(int a, int b)
{
return a + b ;
} void dosome(CXObject* pObj, pf_doSum func)
{
int result = (pObj->*func)(100, 23); printf("result=%d", result);
} int _tmain(int argc, _TCHAR* argv[])
{
CXObject obj ; dosome(&obj, &CXObject::doSum); getchar(); return 0;
}

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuZ3lrMTI1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

能够看到,能够通过一个对象指针,加一个函数指针 调用函数。

这是C++里面也算是非经常常使用的技巧了。

MFC里面系统生成的代码非常多都是用这样的方式。

我们的需求是通过字符串,调用函数,所以就须要建立一个 函数名称 到 函数指针的映射关系。然后就能够字符串查找 函数指针,函数指针调用函数了。

请看完整代码:

// test01.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h" #include <vector>
#include <string> class CXObject ; typedef void (CXObject::*void_func_void)(void); class CXObject
{
public:
//取得类的全部函数的名称
virtual void getMethodNames(std::vector<std::string>& names); //依据名称,取得函数指针
virtual void_func_void getFuncByName(std::string& name);
}; void CXObject::getMethodNames(std::vector<std::string>& names){}
void_func_void CXObject::getFuncByName(std::string& name){return NULL;} class CXMyImpl : public CXObject
{ public: //须要实现的函数
//取得类的全部函数的名称
virtual void getMethodNames(std::vector<std::string>& names); //依据名称,取得函数指针
virtual void_func_void getFuncByName(std::string& name); public://自定义的业务函数。 void doPrint1();
void doPrint2();
}; void CXMyImpl::getMethodNames(std::vector<std::string>& names)
{
names.push_back("doPrint1");
names.push_back("doPrint2");
}
void_func_void CXMyImpl::getFuncByName(std::string& name)
{
void_func_void pFun = NULL ;
if(name.compare("doPrint1") == 0)
pFun = static_cast<void_func_void>(&CXMyImpl::doPrint1) ;
if(name.compare("doPrint2") == 0)
pFun = static_cast<void_func_void>(&CXMyImpl::doPrint2) ;
return pFun ;
} void CXMyImpl::doPrint1()
{
printf("CXMyImpl::doPrint1 be called!!\r\n");
}
void CXMyImpl::doPrint2()
{
printf("CXMyImpl::doPrint2 be called!!\r\n");
} int _tmain(int argc, _TCHAR* argv[])
{
CXObject* obj = new CXMyImpl(); //后面的代码里,并没有CXMyImpl,CXObject里面未定义doPrint1,doPrint2.
//通过字符串的doPrint1运行doPrint1函数。 std::vector<std::string> names ;
obj->getMethodNames(names); for(int idx=0; idx<names.size(); idx++)
{
void_func_void pfun = obj->getFuncByName(names[idx]); (obj->*pfun)();
} getchar(); return 0;
}

执行结果例如以下:

从上面的样例能够看到,事实上是能够模拟出反射的效果的。

假设要C++全然的实现方便有用的反射机制,须要下面几点条件:

1、统一的基类

2、编译器要帮忙

对于第二条条件,能够这样理解:

在上样例中

void CXMyImpl::getMethodNames(std::vector<std::string>& names)
{
names.push_back("doPrint1");
names.push_back("doPrint2");
}
void_func_void CXMyImpl::getFuncByName(std::string& name)
{
void_func_void pFun = NULL ;
if(name.compare("doPrint1") == 0)
pFun = static_cast<void_func_void>(&CXMyImpl::doPrint1) ;
if(name.compare("doPrint2") == 0)
pFun = static_cast<void_func_void>(&CXMyImpl::doPrint2) ;
return pFun ;
}

这两个函数是基类里面定义好了的,算是反射相关的API,可是假设我每写一个类都要自己实现这两个函数。那岂不是要累死。

可是反过来看,这两个函数的功能很easy,代码很有规律。那就是记录当前的类有那些函数,把名字和函数指针相应起来。这个过程全然能够让编译器在编译的时候自己主动为我加上。

还有一方面,因为为了方便演示。这里面用到的业务函数都是 void f(void)类型的。没有參数和返回值,这样显然是不合理的。可是并非不能实现,仅仅只是那样更复杂。绕的圈子很多其它。

在没有这种编译器出现,在没有这种统一基类的类库的情况下,C++的反射,仅仅是停留在兴趣调研的阶段,眼下没看到什么实际价值。个人感觉的哈。

编程基础知识——C++能不能支持Java和ObjC的反射?的更多相关文章

  1. 16第一章 ASP.Net编程基础知识

    第一章        ASP.Net编程基础知识 第一章        ASP.Net编程基础知识 本章首先介绍用ASP.Net技术编制服务器端动态网页所需的网络和HTML标记语言方面的有关知识.然后 ...

  2. SHELL脚本编程基础知识

    SHELL脚本编程基础知识 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Linux之父Linus有一句话很经典:"Talk is cheap, show me the ...

  3. TCP与UDP比较 以及并发编程基础知识

    一.tcp比udp真正可靠地原因 1.为什么tcp比udp传输可靠地原因: 我们知道在传输数据的时候,数据是先存在操作系统的缓存中,然后发送给客户端,在客户端也是要经过客户端的操作系统的,因为这个过程 ...

  4. C#网络编程基础知识

    C#网络编程基础知识一 1.IPAddress类 用于表示一个IP地址.IPAddress默认构造函数 public IPAddress(long address);一般不用 其中Parse()方法最 ...

  5. Jquery真的不难~第一回 编程基础知识

    Jquery真的不难~第一回 编程基础知识   回到目录 前言 说Jquery之前,先来学习一下Javascript(以后简称为JS)语言中的基础知识问题,其时对于每种编程语言来说基础知识都是大同小异 ...

  6. 1.unix网络编程基础知识

    接触网络编程一年多了,最近在系统的学习vnp两本书,对基础知识做一些总结,希望理解的更透彻清晰,希望能有更多的沉淀. 1.套接口地址 针对IPv4和IPv6地址族,分别定义了两种类型的套接口地址:so ...

  7. 你得学会并且学得会的Socket编程基础知识

    这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解. 本文源代码,可以通过这里下载 http://files.cnblog ...

  8. Java基础知识强化之多线程笔记01:多线程基础知识(详见Android(java)笔记61~76)

    1. 基础知识: Android(java)学习笔记61:多线程程序的引入    ~    Android(java)学习笔记76:多线程-定时器概述和使用 

  9. 【Java基础】Java网络编程基础知识

    什么是网络编程 网络编程是通过使用套接字来达到进程间通信目的,那什么是套接字呢?其实套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的 ...

随机推荐

  1. Spring Boot (22) Spring Security

    除了使用拦截器.过滤器实现对没有权限访问的页面跳转到登陆页外,还可以通过框架实现:Spring Security. 使用Spring Security 完成登陆验证: 1.pom.xml添加依赖 &l ...

  2. NGinx 负载均衡作用

    1.负载均衡介绍: 负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助.其工作模式为将外部发送来的请求均匀分配到对称结构中的 ...

  3. Oracle 数据导入导出(imp/exp)

    环境:windows下,oracle11g 1.启动oracle服务 net start OracleDBConsoleorclnet start OracleOraDb11g_home1TNSLis ...

  4. Jquery 获取父页面下指定iframe里的指定元素

    var div1=$("#iframe1",window.parent.document).contents().find("#div1");

  5. 青橙 M4 解锁BootLoader 并刷入recovery ROOT

    首先下载工具链接:https://pan.baidu.com/s/1o9xzTEi密码:7s7a 备用连接:https://pan.baidu.com/s/1bq47TMn 本篇教程教你如何傻瓜式解锁 ...

  6. php加密方法有哪些

    1. MD5加密 string md5 ( string $str [, bool $raw_output = false ] ) 参数 str -- 原始字符串. raw_output -- 如果可 ...

  7. 【PostgreSQL-9.6.3】如何得到psql中命令的实际执行SQL

    当我们在psql界面执行以“\”开头的命令时,数据库会立刻返回执行结果,而不会返回命令的实际执行过程.通过两种方式可以实现执行过程的查看: 方法一:启动psql命令时加“-E”参数 postgres@ ...

  8. C#关闭退出线程的几种方法

    .Application.Exit(); //强制所有消息中止,退出所有的窗体,但是若有托管线程(非主线程),也无法干净地退出: .System.Environment.Exit(); //无论在主线 ...

  9. POJ 3041 - 最大二分匹配

    这道题实现起来还是比较简单的,但是理解起来可能有点困难. 我最开始想到的是贪心法,每次消灭当前小行星最多的一行或一列.然而WA了.Discuss区里已经有高人给出反例. 下面给出正确的解法 我们把行和 ...

  10. react工具库

    采用了react框架后,需要找到一些常用的库,常见的需求比如: 1)react生成二维码 2)react的轮播banner图 随着react的社区的壮大,以上的需求都有专门的库帮我们做这个: 1)re ...