C++ 类型(typeid、RTTI、decltype等)

目录

1,typeid操作符

2,RTTI

3,type_info

4,decltype

5,declval

6,类型别名


1,typeid操作符

语法和sizeof很像,既可以用于变量,也可以用于类型,作用是指出他们的类型。

#include<iostream>
#include <c++/memory>
using namespace std;

class A
{

};

int main()
{
    cout<<typeid(12).name()<<" ";
    cout<<typeid(int).name()<<" ";
    cout<<typeid(1.0).name()<<" ";
    cout<<typeid(double).name()<<" ";
    cout<<typeid('c').name()<<" ";
    cout<<typeid(char).name()<<" ";
    cout<<typeid("s").name()<<" ";
    cout<<typeid(string).name()<<" ";
    cout<<endl;
    cout<<typeid(int*).name()<<" ";
    cout<<typeid(char*).name()<<" ";
    cout<<typeid(double*).name()<<" ";
    cout<<endl;
    cout<<typeid(A).name()<<" ";
    cout<<typeid(A*).name()<<" ";
    return 0;
}

输出:

i i d d c c A2_c NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Pi Pc Pd
1A P1A

PS:

typeid().name()在不同的库中有不同的实现,在vs2019中,上面的代码输出:

int int double double char char char const [2] class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
int * char * double *
class A class A *

2,RTTI

RTTI即Run-Time Type Identification,通过运行时类型识别,程序能够使用基类的指针或引用,来检查这些指针或引用所指的对象的实际派生类型。

#include<iostream>
#include <c++/memory>
using namespace std;

class C
{
public:
    virtual string toString()
    {
        return "class C";
    }
};
class B:public C
{
public:
    string toString()
    {
        return "class B";
    }
};
class A :public B
{
public:
    string toString()
    {
        return "class A";
    }
};

void display(C *p)
{
    cout << p->toString() << " "<<typeid(*p).name()<<endl;
}

int main()
{
    C* p= new A();
    display(p);
    p= new B();
    display(p);
    p= new C();
    display(p);
    return 0;
}

输出:

class A 1A
class B 1B
class C 1C

3,type_info

type_info类的作用就是提供typeid关键字

class type_info
  {
  public:
    /** Destructor first. Being the first non-inline virtual function, this
     *  controls in which translation unit the vtable is emitted. The
     *  compiler makes use of that information to know where to emit
     *  the runtime-mandated type_info structures in the new-abi.  */
    virtual ~type_info();

    /** Returns an @e implementation-defined byte string; this is not
     *  portable between compilers!  */
    const char* name() const _GLIBCXX_NOEXCEPT
    { return __name[0] == '*' ? __name + 1 : __name; }

#if !__GXX_TYPEINFO_EQUALITY_INLINE
    // In old abi, or when weak symbols are not supported, there can
    // be multiple instances of a type_info object for one
    // type. Uniqueness must use the _name value, not object address.
    bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT;
    bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT;
#else
  #if !__GXX_MERGED_TYPEINFO_NAMES
    /** Returns true if @c *this precedes @c __arg in the implementation's
     *  collation order.  */
    // Even with the new abi, on systems that support dlopen
    // we can run into cases where type_info names aren't merged,
    // so we still need to do string comparison.
    bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT
    { return (__name[0] == '*' && __arg.__name[0] == '*')
	? __name < __arg.__name
	: __builtin_strcmp (__name, __arg.__name) < 0; }

    bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT
    {
      return ((__name == __arg.__name)
	      || (__name[0] != '*' &&
		  __builtin_strcmp (__name, __arg.__name) == 0));
    }
  #else
    // On some targets we can rely on type_info's NTBS being unique,
    // and therefore address comparisons are sufficient.
    bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT
    { return __name < __arg.__name; }

    bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT
    { return __name == __arg.__name; }
  #endif
#endif
    bool operator!=(const type_info& __arg) const _GLIBCXX_NOEXCEPT
    { return !operator==(__arg); }

#if __cplusplus >= 201103L
    size_t hash_code() const noexcept
    {
#  if !__GXX_MERGED_TYPEINFO_NAMES
      return _Hash_bytes(name(), __builtin_strlen(name()),
			 static_cast<size_t>(0xc70f6907UL));
#  else
      return reinterpret_cast<size_t>(__name);
#  endif
    }
#endif // C++11

    // Return true if this is a pointer type of some kind
    virtual bool __is_pointer_p() const;

    // Return true if this is a function type
    virtual bool __is_function_p() const;

    // Try and catch a thrown type. Store an adjusted pointer to the
    // caught type in THR_OBJ. If THR_TYPE is not a pointer type, then
    // THR_OBJ points to the thrown object. If THR_TYPE is a pointer
    // type, then THR_OBJ is the pointer itself. OUTER indicates the
    // number of outer pointers, and whether they were const
    // qualified.
    virtual bool __do_catch(const type_info *__thr_type, void **__thr_obj,
			    unsigned __outer) const;

    // Internally used during catch matching
    virtual bool __do_upcast(const __cxxabiv1::__class_type_info *__target,
			     void **__obj_ptr) const;

  protected:
    const char *__name;

    explicit type_info(const char *__n): __name(__n) { }

  private:
    /// Assigning type_info is not supported.
    type_info& operator=(const type_info&);
    type_info(const type_info&);
  };

4,decltype

decltype用于获取一个数据的类型。

template<typename T, typename T2>
T2 getSum(T pBegin,T pEnd)
{
    auto it = pBegin;
    T2 ans = *it++;
    for (; it != pEnd; it++)ans += *it;
    return ans;
}

int main()
{
    vector<int>v{ 1,2,5 };
    cout << getSum<decltype(v.begin()),int>(v.begin(),v.end());
    return 0;
}

5,declval

如果一个类没有构造函数,那么对它使用decltype就会遇到困难。

declval可以解决这个困难,它的用法是“看似声明了一个变量”,实际上没有这个变量,只有类型信息,这样就可以用decltype了。

template<typename T, typename T2>
T2 getSum(T pBegin,T pEnd)
{
    auto it = pBegin;
    T2 ans = *it++;
    for (; it != pEnd; it++)ans += *it;
    return ans;
}

int main()
{
    vector<int>v{ 1,2,5 };
    cout << getSum<decltype(declval<vector<int>>().begin()), int > (v.begin(), v.end());
    return 0;
}

6,类型别名

C++为类型建立别名的方式有三种。

(1)使用预处理器:

# define BYTE char

这样预处理器将在编译程序时用 char 替换所有的 BYTE ,从而使 BYTE 成为 char 的别名

(2)使用关键字 typedef 

例如要将 byte 作为 char 的别名,可以这样做:
 typedef  char byte;

下面是通用格式:
 typedef typeName aliasName ;.

换句话说,如果要将 aliasName 作为某种类型的别名,可以声明 aliasName ,如同将 aliasName 声明为这种类型的变量那样,然后在声明的前面加上关键字 typedef 。

例如,要让 byte_pointer 成为 char 指针的别名,可将byte_pointer 声明为 char 指针,然后在前面加上 typedef 
typedef  char * byte_pointer;

也可以使用#define ,不过声明一系列变量时,这种方法不适用。

typedef 方法不会有这样的问题,它能够处理更复杂的类型别名,这使得与使用#define 相比,使用 typedef是一种更佳的选择,有时候这也是唯一的选择。

(3)using

using

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值