#define、typedef 和 using之间的联系和区别

目录

一 、#define

1. 含义

2. 用处

1. 条件编译

2. 解宏

3. 文件包含

二 typedef

1. 含义

2. 用处

1. 数据类型别名

2. 指针别名

3. 结构体别名

4. 与平台无关的数据类型

三 using

1. 含义        

2. 用处

1. 权限管理

2.类型重命名

3. 继承体系中,改变部分接口函数的继承权限

四 #define和typedef的区别


一 、#define

1. 含义

        #define主要用来做宏定义,主要格式为:

#define 标识符 常量

        宏定义后的标识符就是代表常量的意思,再以后的代码当中,使用标识符的地方都被替换成常量了,这里的常量可以是字符、字符串、变量、类型、表达式等等。值得注意的是,宏定义定义的标识符是在程序编译之前的预处理阶段进行替换的,也就是说在预处理阶段,已经把程序中所有的标识符全部替换成了常量,因此在程序运行阶段是调试不了该标识符的。

2. 用处

1. 条件编译

        所谓条件编译就是宏开关,当多个厂家找你开发一套程序,而这一套程序的逻辑恰好一样的,只是有些地方需要有不同的显示,你会选择统是开发多个项目吗,这是一个很蠢的做法,因为这几套程序的代码90%是相同的,你同时维护这么多套程序会很占用你的内存资源的,所以这个时候宏开关(条件编译)就起到了很好的作用,它相当于在你的程序开头定义一个宏变量,然后在你需要转换不同厂家不同逻辑代码的地方进行判断就可以了。

#include<iostream>
using namespace std;

# define GOOGLE 0
# define FACEBOOK 1



void main(){
    string result = "0";

#ifdef GOOGLE
    result = "I am a google company!";
#endif
#if FACEBOOK
    result = "I am a facebook company!";
#endif


    cout<<result;

}

当GOOGLE = 0时,打印的结果是GOOGLE:

 当FACEBOOK = 0时,打印的结果是FACEBOOK:

 

2. 解宏

#define宏定义的变量的作用域是整个程序,当然,你也可以通过#undef来解宏,就是在解宏后,解宏后面代码中的这个宏定义标识符就失效了。

#include<iostream>
using namespace std;

# define GOOGLE 0
# define FACEBOOK 1



void main(){
#ifdef GOOGLE
    result = "I am a google company!";
#endif



#if FACEBOOK
    result = "I am a facebook company!";
#endif

#undef FACEBOOK                                    // 解宏

#ifdef FACEBOOK                                    // 失效
    result = "I am a facebook company!";
#endif

    cout<<result;
}

我们可以看一下在解宏FACEBOOK后编译器的界面显示,QT界面上显示了解宏后再去判断宏的话是没有起到效果的:

3. 文件包含

宏定义还可以避免我们在开发程序时头文件相互引用,这样做的好处就是减少编译器的工作量

#ifndef _HEADFILE_
#define _HEADFILE_

...

#endif

先判断有没有包含头文件_HEADFILE_,如果没有的话就引入,例如在Test.h文件中

#ifndef TEST_H
#define TEST_H

...

#endif // TEST_H

二 typedef

1. 含义

        用typedef来给类型起一个别名,主要格式为:

typedef 类型 别名

类型可以是基本数据类型,也可以是结构体等等。

2. 用处

1. 数据类型别名

        定义了一个类型符号INT_32,用来表示int数据类型,在接下来的变量定义中可以使用该别名INT_32进行操作;

typedef int INT_32;

INT_32 A = 9;

2. 指针别名

        定义了一个类型符号PCHAR,表示char指针,用PCHAR来定义Serven_3和Serven_4就可以让Serven_3 和 Serven_4成为char类型指针。

typedef char* PCHAR;

char Serven_1 = 's';
char Serven_2[] = "123456";

PCHAR Serven_3, Serven_4;


Serven_3 = &Serven_1;            // 指向Serven_1
Serven_4 = &Serven_2;            // 指向Serven_2

        值得注意的是   PCHAR Serven_3, Serven_4  等价于  char *Serven_3, *Serven_4  ,它跟  char *Serven_3, Serven_4  不一样,前者是两个char类型的指针,后者是一个char类型指针,一个char类型变量。

        在Serven_3前面加上const,会变成一个指针常量,指向的变量地址不能修改,但可以通过执政去修改变量的值。

const PCHAR Serven_5;

3. 结构体别名

        以往定义一个结构体如下所示

struct Student{
    int StuNo;
    char StuName[20];
};

        如果我们需要实例化结构体对象,那么操作是:

struct Student Ser_stu;        // 实例化一个结构体变量

        现在我们可以通过typedef来给结构体一个别名

typedef struct Student{
    int StuNo;
    char StuName[20];
}Stu;

        这下我们来实例化结构体对象的操作可以为:

Stu Ser_stu;            // 实例化一个结构体变量

4. 与平台无关的数据类型

        在日常开发中,特别是在嵌入式单片机的开发中,我们可以通过定义一些平台没有提供的数据类型,例如:

typedef unsigned char BYTE;              // 别名一个BYTE类型
typedef unsigned int UINT_32;            // 别名一个32长度的整型类型

三 using

1. 含义        

        using的作用是给数据类型起别名,它的作用跟typedef相似,主要格式为:

using 别名 = 类型等

2. 用处

1. 权限管理

        配合命名空间,对命名空间权限进行管理

using namespace std;                // 释放整个命名空间到当前作用域
using::string;                      // 释放某个变量当前作用域

        我相信你在刚开始接触C/C++语言的时候都会遇到过下面的代码,即没有加上命名空间权限using namespace std; 这会导致main函数中string是无法标识的,解决方案有两个,要么加上整个命名空间权限,要么在string前面加上std::。

#include<iostream>

void main(){
    string serven;
}

2.类型重命名

        给string类型起一个别名,这样的格式看起来比typedef更加直观吧。

using Dstring = std::string;

        可以给一个很长的类名起一个别名:

using ILV = I_LOVE_YOU;

3. 继承体系中,改变部分接口函数的继承权限

        当我们在面向对象编程的时候,往往会继承别的类,继承有三种方式,分别是公有继承(public)、私有继承(private)、保护继承(protected)。在这三种继承中,私有继承后,父类的所有成员属性和方法都成为了派生类的私有成员,这会导致派生类实例化的对象是不能访问这些成员属性和方法的,在这个时候,using就起到作用了,使用using就可以将其变成公有成员

class Parents{
    Parents(){}
    ~Parents(){}
public:
    int serven1;
public:
    int Speak(){
    cout<<"I am taking!";    
    }

};



class Child(): private Parents{
public:
    using Parents::Speak();

}



void main(){

    Child Serven2 = new Child();
    Serven2.Speak();                        // 可以调用,因为使用了using,并且在子类中的public        
    Serven2.serven1;                        // 不能调用,因为是私有属性
}

四 #define和typedef的区别

        我们只看它们的第一个无别,typedef的别名前面加上const后表示定义的变量为指针常量,而define定义的表示常量指针。

#include<iostream>
using namespace std;

typedef int* PINT;
#define pint int*


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);


    const PINT serv1;               // 相当于指针常量
    PINT serv1;
    const pint serv2;               // 相当于常量指针

    int s = 7;
    int d = 3;

    serv1 = &s;
    serv2 = &s;

    cout<<*serv1<<endl;
    cout<<*serv2<<endl;

    serv1 = &d;                    // 出错,因为指针常量不能指向别的变量地址了
    serv2 = &d;

    cout<<*serv1<<endl;
    cout<<*serv2<<endl;


    *serv1 = 6;
    //*serv2 = 6;                  // 出错,因为常量指针不能修改变量的值

    cout<<*serv1<<endl;
    cout<<*serv2<<endl;



    PINT SERVEN1, SERVEN2;          // 表示SERVRN1和SERVEN2两个都是指针变量
    SERVEN1 = &d;
    SERVEN2 = &d;

    pint SERVEN3, SERVEN4;          // 只是做简单的替换,SERVEN3是指针变量,SERVEN4是int变量
    SERVEN3 = &d;
    SERVEN4 = 9;


    cout<<*SERVEN1<<endl;
    cout<<*SERVEN2<<endl;
    cout<<*SERVEN3<<endl;
    cout<<SERVEN4<<endl;

    return a.exec();
}

运行结果:

另外一个区别就是:

1. typedef是一个语句,后面要加上分号

2. #define是一个关键字,只是在做标识符的替换

3. typedef是在运行期间进行的,#define是在预编译期间进行的。

4. typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:

typedef static int INT2; //不可行

   编译将失败,会提示“指定了一个以上的存储类”。

5. 在有指针的情况下,typedef会好一些,因为下面代码中,PCHARdef仅仅是做字符串的替换,所以SERVEN3是一个指针,而SERVEN4是一个char类型的变量。PCHARtyp定义的两个SERVEN1和SERVEN2都是插入指针。

typedef char* PCHARtyp;
#define PCHARdef char*


PCHARtyp SERVEN1, SERVEN2;
PCHARdef SERVEN3, SERVEN4;

喜欢就给小编点个赞吧,欢迎关注微信公众号 “三贝勒文子

  • 34
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 45
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三贝勒文子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值