typeid为type_info友元函数

本文详细介绍了typeid函数的作用和使用原理,包括如何通过typeid函数获取变量类型、比较类型等,并解释了typeid函数与type_info类的关系。
typeid函数
该函数的主要作用就是让用户知道当前的变量是什么类型的,比如使用typeid(a).name()就能知道变量a是什么类型的。因为typeid()函数是一个返回类型为const typeid_info&类型的函数,所以下面先对type_info类作下介绍
type_info类
该类的具体实现方式依编译器而定,但一般都有如下的成员定义
class type_info
{private:
type_info(const type_info &);
type_info& operator =(const type_info&); //type_info类的复制构造函数和赋值运算符是私有的。

public:
virtual ~type_info(); //析构函数
bool operator = =(const type_info&) const; //在type_info类中重载了= =运算符,该运算符可以比较两个对象的类型是否相等。
bool operator !=(const type_info&)const; //重载的!=运算符,以比较两个对象的类型是否不相等
const char * name() const; //使用得较多的成员函数name,该函数反回对象的类型的名字。前面使用的typeid(a).name()就调用了该成员函数
bool before(const type_info&);};
因为type_info类的复制构造函数和赋值运算符都是私有的,所以不允许用户自已创建type_info的类,比如type_info A;错误,没有默认的构造函数。唯一要使用type_info类的方法就是使用typeid函数。
typeid函数怎样创建type_info类的对象
该函数返回type_info类对象的引用,即形式为const type_info& typeid();因此也可以说typeid函数是type_info类的一个引用对象,可以访问type_info类的成员。但因为不能创建type_info类的对象,而typeid又必须返回一个类型为type_info类型的对象的引用,所以怎样在typeid函数中创建一个type_info类的对象以便让函数返回type_info类对象的引用就成了问题。这可能是把typid函数声明为了type_info类的友元函数来实现的,默认构造函数是私有的并不能阻止该类的友元函数创建该类的对象。所以typeid函数如果是友元的话就可以访问type_info类的私有成员,从而可以创建type_info类的对象,从而可以创建反回类型为type_info类的引用。举个例子class A{private:A(){} A(const A&){} A& operator =(const A&){} friend A& f();};这里把类A的默认构造函数,复制构造函数和赋值操作符定为私有从而防止创建类A的对象,但函数f()是类A的友元,所以在函数f()中可以创建类A的对象。同时为了实现函数f()返回的对象类型是A的引用,就必须在函数f中创建一个类A的对象以作为函数f的返回值,比如函数f可以这样定义A& f(){A ma; cout<<”f”<<endl; return ma}。
因为typeid函数是type_info类的对象,也就是说可以用该函数访问type_info类的成员,即type_info类中重载的= =和!=运算符,name()和before()成员函数,比如typid(a).name()和typid(a) == typid(b)等等。
typeid函数的使用原理
该函数的形式为type_info& typeid(object)其中object是任何类型的对象,可以是内置类型和用户创建的类类型。可以看出typeid即是一个函数,同时他也是type_info类的对象,即typeid可以访问类type_info类的成员,也可以做为一个单独的函数来使用。做个简单的例子,比如
class A{private: A(){b=3;cout<<”A”<<endl;} //私有的默认构造函数
public: void name(){cout<<”NA”<<endl;} int b;
friend A f();}; //函数f()是类A的友元,因此在f中可以创建类A的对象。
A f() //函数f()在这里即是类A的一个对象,也是一个单独的函数。
{ A m; //创建类A的对象,因为函数f是类A的友元,因此可以创建类A的对象
cout<<”F”<<endl; return m;}
main()
{ f().name(); //函数f()作为类A的对象使用,这里要注意程序的执行顺序,首先执行函数f()中的语句A m,因此调用类A的默认构造函数输出A,然后执行A m;后面的语句,输出F,再然后调用类A中的成员函数name输出NA.
f(); } //函数f()单独作为函数使用。
我们创建一个类A,其中A的默认构造函数是私有的,也就是说不能用默认构造函数创建类A的对象。函数f()是类A的友元,且反回一个类A的对象,因为f()函数是类A的友元,所以在函数f中可以用默认构造函数创建类A的对象,这时函数f()同时是一个函数,也是类A的对象,因此也可以访问类A中的成员。
typeid函数使用方式

、使用type_info类中的name()成员函数反回对象的类型的名称。其方法为:typeid(object).name()其中object是要显示的对象的类型名,该函数反回的名字因编译器而定。这里要注意的就是使用方式一中提到的虚函数类型的问题,即如果有类A,且有虚函数,类B,C,D都是从类A派生的,且都重定义了类A中的虚函数,这时有类A的指针p,再把对象类B的对象的地址赋给指针p,则typeid(p).name()将反回的类型将是A*,因为这里的p表示的是一个指针,该指针是类型为A的指针,所以反回A*,而typeid(*p).name()将反回B,因为指针p是指向类B的对象的,而*p就表示的是类B的对象的类型,所以反回B。

2)、使用type_info类中重载的= =与!=比较两个对象的类型是否相等。使用该方法需要调用类type_info中重载的= =和!=操作符,其使用方法为typid(object1)= =typid(object2);如果两个对象的类型相等则反回1,如果不相等则为0。这种使用方法通常用于比较两个带有虚函数的类的对象是否相等,比如有类A,其中定义有虚函数,而类B,类C,类D,都是从类A派生而来的且重定义了该虚函数,这时有个类A的指针p和p1,按照虚函数的原理,基类的指针可以指向任何派生类的对象,在这时就有可能需要比较两个指针是否指向同一个对象,这时就可以这样使用typeid了,typeid(*p)= =typeid(*p1);这里要注意的是typeid(*p)与typeid(p)是指的不同的对象类型,typeid(p)表示的是p的类型,在这里p是一个指针,这个指针指向的是类A的对象,所以p的类型是A*,而typeid(*p)则不一样,*p表示的是指针p实际所指的对象的类型,比如这里的指针p指向派生类B,则typeid(*p)的类型为B。所以在测试两个指针的类型是否是相等时应使用*p,即typeid(*p)= =typeid(*p1)。如果是typeid(p)= =typeid(p1)的话,则无论指针p和p1指向的什么派生类对象,他们都是相等的,因为都是A *的类型。
基本语法与结构 变量定义与基本数据类型(int, float, double, char, bool) 类型推导(auto, decltype) 运算符(算术、逻辑、比较、位运算等) 控制结构:if-else, switch, for, while, do-while 函数定义、参数传递(值传递、引用传递、指针传递) 函数重载与默认参数 const 关键字的使用(常量、常量成员函数) 2. 面向对象编程(OOP) 类与对象的定义 构造函数与析构函数 成员访问修饰符(public, private, protected) 封装、继承、多态(虚函数、抽象类) 运算符重载 this 指针 静态成员(变量与函数) 友元函数与友元类 3. 指针与引用 指针的基本操作(定义、赋值、解引用) 指针与数组的关系 引用的使用(别名机制) 指向函数的指针 nullptr 的使用 4. 内存管理 动态内存分配(new / delete, new[] / delete[]) 内存泄漏与如何避免 智能指针(std::unique_ptr, std::shared_ptr, std::weak_ptr) RAII(资源获取即初始化)模式 5. 标准模板库(STL) 容器: 序列容器:vector, list, deque 关联容器:set, map, multiset, multimap 无序容器:unordered_set, unordered_map 迭代器(begin(), end(), rbegin(), rend()) 算法(sort, find, copy, transform 等) 函数对象(Functor)与 Lambda 表达式 std::pair, std::tuple, std::optional7. 命名空间 namespace 的定义与使用 嵌套命名空间 using 声明与 using namespace 8. 异常处理 try, catch, throw 异常安全编程 noexcept 说明符 9. 预处理器与宏 #include, #define, #ifdef, #ifndef 宏定义与函数宏 防止头文件重复包含(#pragma once 或 #ifndef ... #define ...) 10. 文件操作 输入输出流(iostream, fstream) 文件读写(ifstream, ofstream, fstream) 文本与二进制模式 11. 类型转换 static_cast dynamic_cast reinterpret_cast const_cast 给出一个详细的类保护上述知识点
最新发布
08-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值