#ifndef #define #endif typedef typename

1.ifndef define endif

我们经常在c++的头文件中见到一堆#ifndef #define #endif这种标识。这些到底是用来干啥的?
在一个比较大的工程里,可能会出现一个头文件被多个文件同时include的情况。然后当这些文件编译链接成一个可执行文件的时候,会出现大量重复定义的错误。

比如我们打开stl库中vector源码,开头就有这么一个定义

#ifndef _LIBCPP_VECTOR
#define _LIBCPP_VECTOR
.......

然后文件最后定义

#endif  // _LIBCPP_VECTOR

ifndef,意为if not define。意思是当文件编译到该行,如果该文件还没被编译过,那么程序将define _LIBCPP_VECTOR,并执行后面的代码。反之将不会再次编译文件。

endif出现在程序的最后,与ifndef或ifdef配对出现,作为结束的标识符。

2.typedef定义类型别名

typedef,很容易就能明白他的作用是type define。我们可以看看他的几个常见用法。

比如我们在stl源码中,经常看到这种类似的代码

public:
    typedef _Allocator                               allocator_type;
    typedef allocator_traits<allocator_type>         __alloc_traits;
    typedef typename __alloc_traits::size_type       size_type;
protected:
    typedef _Tp                                      value_type;
    typedef value_type&                              reference;

上面的例子,就是为类别举个别名。比如将_Tp起个别名为value_type。这样做最大的好处就是可以非常简单明了的读懂变量的含义。

我们也可以自己举一个例子。

#include<iostream>
using namespace std;
typedef int Price;

void func() {
    Price price = 10;
    cout<<"book's price is: "<<price<<endl;
}

int main(int argc, char const *argv[])
{
    func();
    return 0;
}

这样在其他地方,我们就可以将Price代替int当做一种类型直接使用了,这样代码的可读性就得到了较大提高。

3.typedef定义平台类型

typedef定义平台类型也是我们在各种类库源码中常见的一种方式。

以size_t为例,_size_t.h头文件定义如下

#ifndef _SIZE_T
#define _SIZE_T
#include <machine/_types.h> /* __darwin_size_t */
typedef __darwin_size_t        size_t;
#endif  /* _SIZE_T */

可以看到size_t其实就是__darwin_size_t。

如果我们再查看__darwin_size_t

#if defined(__SIZE_TYPE__)
typedef __SIZE_TYPE__           __darwin_size_t;        /* sizeof() */
#else
typedef unsigned long           __darwin_size_t;        /* sizeof() */
#endif

上面这段代码告诉我们,如果定义了__SIZE_TYPE__类型,那么__darwin_size_t就是__SIZE_TYPE__。如果没有,就将unsigned long定义为__darwin_size_t。

宏定义就是简单的字符串替换。与定义宏相比,typedef是定义了一种类型的新别名,而不是单纯的字符串替换,所以他比宏要来的稳妥。

4.typedef struct

typedef还可以与struct配合使用,为struct定义别名。

typedef struct Teacher {
    string name;
    int age;
    Teacher(string tname, int tage): name(tname), age(tage) {}
}tea;

void func() {
    tea t1("lili", 26);
    cout<<"name is: "<<t1.name<<", age is: "<<t1.age<<endl;
}

int main(int argc, char const *argv[])
{
    func();
    return 0;
}

输出结果:

name is: lili, age is: 26

上面的代码为Teacher结构体定义了别名tea,后面就可以直接使用tea。
如果struct前面没有typedef关键字,那么tea将会是一个变量而不是别名。具体可以看下面的代码

struct Teacher {
    string name;
    int age;
}tea;

void func() {
    tea.name = "lili";
    tea.age = 26;
    cout<<"name is: "<<tea.name<<", age is: "<<tea.age<<endl;
}

int main(int argc, char const *argv[])
{
    func();
    return 0;
}

此时代码的输出为

name is: lili, age is: 26

应该可以看出两者的区别

typedef typename

我们还经常看到typedef typename连在一起的用法,比如我们在vector的源码中,能看到大段这种定义:

    typedef typename __base::__alloc_traits          __alloc_traits;
    typedef typename __base::reference               reference;
    typedef typename __base::const_reference         const_reference;
    typedef typename __base::size_type               size_type;
    typedef typename __base::difference_type         difference_type;
    typedef typename __base::pointer                 pointer;
    typedef typename __base::const_pointer           const_pointer;

上面为什么要加上typename的关键字?
主要是在类型实例化之前,编译器并不知道像__base::size_type 这种是什么东东,因为__base引用size_type,有三种可能情况:
1.size_type是__base的静态成员变量。
2.size_type是__base的静态函数。
3.size_type是__base的嵌套内部类。

我们通过typename关键字,就明确告诉编译器,size_type是第三种情况为嵌套内部类,而不是前面两种情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值