C++中的类型擦除

本文详细介绍了C++中的类型擦除概念,通过分析boost::any和boost::function库,阐述如何实现类型擦除以达到存储和调用不同类型的对象。文章以简化版的any和function为例,讲解了如何利用模板和抽象类实现类型擦除,同时保持类型安全。
摘要由CSDN通过智能技术生成

关于类型擦除,在网上搜出来的中文资料比较少,而且一提到类型擦除,检索结果里就跑出很多 Java 和 C# 相关的文章来(它们实现“泛型”的方式)。所以,这一篇我打算写得稍微详细一点。 注意,这是一篇读书笔记(《C++ template metaprogramming》第9.7小节和《C++ テンプレートテクニック》第七章),里面的例子都来自原书。


在 C++ 中,编译器在编译期进行的静态类型检查是比较严格的,但有时候我们却希望能“避过”这样的类型检查,以实现更灵活的功能,同时又尽量地保持类型安全。听起来很矛盾,而且貌似很难办到。但其实 C++ 的库里已经有很多这样的应用了。比如,著名的 boost::function 和 boost::any 。当我们定义一个 function<void(int)> fun 对象,则 fun 即可以存储函数指针,又可以存储函数对象,注意,这两者是不同“类型”的,而且函数对象可以是无限种类型的,但这些不同类型的“东西”都可以存在同一类型的对象 fun 中,对 fun 来说,它关心的只是存储的“对象”是不是“可以按某种形式(如void(int))来调用”,而不关心这个“对象”是什么样的类型。有了 function 这样的库,在使用回调和保存可调用“对象”的时候,我们就可以写出更简单且更好用的代码来。再举一个例子,boost::any 库。any 可以存储任何类型的“对象”,比如 int ,或是你自己定义的类 MyCla 的对象。这样我们就可以使一个容器(比如 vector<boost::any> )来存储不同类型的对象了。

这些库所表现出来的行为,就是这篇文章中要提到的类型擦除,类型擦除可以达到下面两个目的:

  • 用类型 S 的接口代表一系列类型 T 的的共性。
  • 如果 s 是 S 类型的变量,那么,任何 T 类型的的对象都可以赋值给s。

好了,下面我们具体地看看类型擦除是怎么回事,在这个过程中,我们先以 any 这个类为依托来解释(因为它比较“简单”,要解释的额外的东西比较少)。

any 这个类需要完成的主要任务是:1. 存储任何类型的变量 2. 可以相互拷贝 3. 可以查询所存变量的类型信息 4. 可以转化回原来的类型(any_cast<>)

对于其中,只要说明1和2 ,就能把类型擦除的做法展示出来了,所以,我们这里只实现一个简单的,有1、2、3功能的any类(3是为了验证)。

首先,写个最简单的“架子”出来:

 

class my_any { 
    ?? content_obj; 
public: 
    template <typename T> 
    my_any(T const& a_right); 
}; 

这里,由于 my_any 的拷贝构造函数使用的是模板函数,因此,我们可以任何类型的对象来初始化,并把该对象的复本保存在 content_obj 这个数据成员中。那么,问题是,content_obj 用什么类型好呢?

首先我们会想到,给 class 加个模板参数 T ,然后……,不用然后了,这样的话,使用者需要写这样的代码:

my_any<someType> x = y;

不同的 y 会创造出不同类型的 x 对象,完全不符合我们要将不同类型对象赋给同一类型对象的初衷。接着,我们会想到用 void *(C 式的泛型手法啊……),但这样的话,我们就会完全地丢失原对象的信息,使得后面一些操作(拷贝、还原等)变得很困难,那么,再配合着加入一些变量用于保存原对象信息?你是说用类似“反射”的能力?好吧,我只好说,我以为 C++ 不存在原生的反射能力,以我浅薄的认识,我只知道像 MFC 式的侵入式手法……,嗯,此路不通。

这个困境的原因在于,在C++ 的类中,除了类模板参数之外,无法在不同的成员(函数、数据成员)之间共享类型信息。在这个例子中,content_obj 无法得知构造函数中的 T 是什么类型。所以类型无法确定。

为了妥善保存原对象复本,我们定义两个辅助类,先上代码(来自 boost::any 的原码):

class placeholder 
{ 
public: // structors 
    virtual ~placeholder()      { 
    } 
public: // queries 
    virtual const std::type_info & type() const = 0; 
    virtual placeholder * clone() const = 0; 
}; 

template<typename 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值