在JAVA中,有Object类,是所有类的基类,在很多时候,为了设计出通用的程序,需要将Object类作为函数参数或者返回类型(这样可以指向任何数据对象)。在C++17中,也出现了这样一个类,即 any 类。
any a(10);
any b("abandon");
//不是下面这种
any<int> a(10);
any<std::string> b("abandon");
如果用了模版参数变成 any<int> any_value(10) 这样,那 any_value 就确定是 int 类型,并且在使用时还需要传类型作为模版参数。所以,any 必须不能是模板类。那么问题来了,如果 any 不是模板类,它怎么才能泛化的保存各种类型呢?答案就在 虚基类和它的派生模板类 。
因为any不是模板类不能保存泛型数据,那就需要将原数据用一种容器包起来,然后让any持有一个指针,指向这个容器。那么很明显,这个容器类必须是模板类,因为这样它才能保存泛型数据,而又因为any不是模板类,它的任何数据成员都不能是泛型的,那就需要一个基类,让any持有这个基类的指针,而“容器”从这个基类派生并带模版参数。这样就解决了问题,即让原来需要泛型化存储数据的的any不泛型化,转而定义一种泛型化容器来保存数据,而any自己握住该泛型化容器基类的指针指向这个泛型化的容器。太绕了...绕这么一圈的目的,就是为了开始提到的涉及初衷:提供一种动态的数据类型,并接受单个对象的同时能够获得它的类型。
// Any类型:可以接收任意数据的类型
class Any
{
public:
Any() = default;
~Any() = default;
Any(const Any&) = delete;
Any& operator=(const Any&) = delete;
Any(Any&&) = default;
Any& operator=(Any&&) = default;
// 这个构造函数可以让Any类型接收任意其它的数据
template<typename T> // T:int Derive<int>
Any(T data) : base_(std::make_unique<Derive<T>>(data))
{}
// 这个方法能把Any对象里面存储的data数据提取出来
template<typename T>
T cast_()
{
// 我们怎么从base_找到它所指向的Derive对象,从它里面取出data成员变量
// 基类指针 =》 派生类指针 RTTI
Derive<T>* pd = dynamic_cast<Derive<T>*>(base_.get());
if (pd == nullptr)
{
throw "type is unmatch!";
}
return pd->data_;
}
private:
// 基类类型
class Base
{
public:
virtual ~Base() = default;
};
// 派生类类型
template<typename T>
class Derive : public Base
{
public:
Derive(T data) : data_(data)
{}
T data_; // 保存了任意的其它类型
};
private:
// 定义一个基类的指针
std::unique_ptr<Base> base_;
};
思考一个问题:
C++中任意类型的数据,可以用哪些方法? template、void*、union结构体
union结构体,只能存放固定种类的值,没有扩展性
void* :C++是强类型语言,用void* 保存后丢失了类型的信息,很难保证类型安全。(什么是类型安全?类型安全很大程度是可以等价为内存安全,类型安全的代码不会去访问自己没有授权的内存区域,类型安全是指同一段内存在不同的地方,会被强制要求使用相同的办法来解释(内存中的数据是用类型来解释的))Java语言是类型安全的,除非强制类型转换。C语言不是类型安全的,因为同一段内存可以用不同的数据类型来解释,比如1用int来解释就是1,用boolean来解释就是true。
int a = 10;
void* p = &a;
double* dp = (double*)p;
cout << *dp << endl;
输出:-9.25596e+61