(原创)c++中的类型擦除

2022-11-25,,

c++11 boost技术交流群:296561497,欢迎大家来交流技术。

关于类型擦除,可能很多人都不清楚,不知道类型擦除是干啥的,为什么需要类型擦除。有必要做个说明,类型擦除就是将原有类型消除或者隐藏。为什么要擦除类型?因为很多时候我不关心具体类型是什么或者根本就不需要这个类型,通过类型擦除我们可以获取很多好处,比如使得我们的程序有更好的扩展性、还能消除耦合以及消除一些重复行为,使程序更加简洁高效。归纳一下c++中类型擦除方式主要有如下五种:

第一种:通过多态来擦除类型

第二种:通过模板来擦除类型

第三种:通过某种容器来擦除类型

第四种:通过某种通用类型来擦除类型

第五种:通过闭包来擦除类型

第一种类型隐藏的方式最简单也是我们经常用的,通过将派生类型隐式转换成基类型,再通过基类去多态的调用行为,在这种情况下,我不用关心派生类的具体类型,我只需要以一种统一的方式去做不同的事情,所以就把派生类型转成基类型隐藏起来,这样不仅仅可以多态调用还使我们的程序具有良好的可扩展性。然而这种方式的类型擦除仅仅是部分的类型擦除,因为基类型仍然存在,而且这种类型擦除的方式还必须是继承方式的才可以,而且继承使得两个对象强烈的耦合在一起了,正是因为这些缺点,通过多态来擦除类型的方式有较多局限性效果也不好。这时我们通过第二种方式擦除类型,以解决第一种方式的一些缺点。通过模板来擦除类型,本质上是把不同类型的共同行为进行了抽象,这时不同类型彼此之间不需要通过继承这种强耦合的方式去获得共同的行为了,仅仅是通过模板就能获取共同行为,降低了不同类型之间的耦合,是一种很好的类型擦除方式。然而,第二种方式虽然降低了对象间的耦合,但是还有一个问题没解决,就是基本类型始终需要指定,并没有消除基本类型,例如,我不可能把一个T本身作为容器元素,必须在容器初始化时就要知名这个T是具体某个类型。这时多么希望有一种通用的类型啊,可以让我的容器容纳所有的类型,就像c#和java中的object类型一样,是所有类型的基类。c++中没有这种object类型怎么办?也许有人想到了,可以用boost.variant类型,是的,boost.variant可以把各种不同的类型包起来,从而让我们获得了一种统一的类型,而且不同类型的对象间没有耦合关系,它仅仅是一个类型的容器。让我们看看怎么用boost.variant来擦除类型。

struct blob
{
    const char *pBuf;
    int size;
};
//定义通用的类型,这个类型可能容纳多种类型
typedef boost::variant<double, int, uint32_t, sqlite3_int64, char*, blob, NullType>Value;

vector<Value> vt; //通用类型的容器,这个容器现在就可以容纳上面的那些类型的对象了
vt.push_back(1);
vt.push_back("test");
vt.push_back(1.22);
vt.push_back({"test", 4}); 

View Code