typedef,static,const用法
一.typedef主要功能是定义一个已存在类型的别名,但是和宏并存
宏与typedef区别
1.宏定义只是简单的字符串替换
2.typedef定义的类型是类型的别名,typedef后面是一个整体声明,是不能分割的一个整体,具有一定的封装性,不是简单的字符串替换
看下面的例子:
#define PSTR_MACRO char*
typedef char* PSTR
int main()
{
PSTR piVar1,piVar2;
PSTR_MACRO piVar3,piVar4;
int iVar = 100;
piVar1 = &iVar;
piVar2 = &iVar;
piVar3 = &iVar;
piVar4 = &iVar;
printf("piVar1 = %0X\r\n",piVar1);
printf("piVar2 = %0X\r\n",piVar2);
printf("piVar3 = %0X\r\n",piVar3);
printf("piVar4 = %0X\r\n",piVar4);
}
输出piVar1 = 19FC78
piVar2 = 19FC78
piVar3 = 19FC78
piVar4 =78
typedef主要为复杂的声明定义简单的别名,它本身是一种存储类的关键字,与auto,extern,mutable,static,register等关键字不能出现在同一个表达式中,如typedef static int nValue
typedef的其它用途
1.用在旧的C代码中,声明struct新对象时,必须带上struct,即形式为struct结构体对象名,例如
struct tagPOINT 为了实现在结构体使用过程中少写声明头部分的struct,可采用 typedef struct tagPOINT
{ {
int x; int x;
int y; int y;
}; }POINT;
struct tagPOINT pl; POINT pl;
在C++中,typedef的这种用途不是很大,但理解了它,对掌握以前的旧代码还是有帮助的
2.另外一个用途就是定义与机器无关的类型,保障代码具有较好的跨平台特性。例如,可定义一个名为REAL_NUM的浮点类型,在目标机器上它可以获得最高的精度
typedef long double REAL_NUM
在不支持long double的机器上,通过typedef可采用如下定义
typedef double REAL_NUM
对于连double都不支持的机器上,通过typdedef可采用如下定义
typedef float REAL_NUM;
采用typedef实现数据类型的定义,只需对typedef本身进行修改,不用对源代码做任何修改,便可以在每一种平台上编译这个使用REAL_NUM类型的应用程序
3.为复杂的声明定义一个简单的名称,简化代码。这一功能可增强代码的可读性和标识符的灵活性
例如
int*(*paFunc[6])(char* pszInput) 简化后为typedef int* (*pFunc)(char* pszInput) pFunc paFunc[6]
typedef BOOL *CallBackFunc(const char* pszData,const int nDatalength); CallBackFunc m_pCallBackFunc;
二.static关键字
static有3种用法:静态局部变量,静态全局变量/函数和静态成员变量/函数
1.静态局部变量
static变量分配在全局静态存储区域,在程序的整个运行期间都不会释放。在初次运行时进行初化工作,且只初始化一次。如果不赋初值,编译器会自动赋值0或空字符
static局部变量具有“记忆性”与生存期的“全局性”
记忆性是指在两次函数调用时,在第二次调用进入时,能保持第一次调用时退出时的值
全局性是指一存周期从程序运行时开始,直到程序退出时结束
2.静态全局变量/函数
静态全局变量/函数的静态指的不是存储方式,而是指函数(变量)的作用域为本文件,不能被其他文件所访问
对于全局变量无论是否被static修饰限制,它的存储区域都是静态存储区,生存期都是全局的。
使用静态函数的好处是:不同的程序员编写不同的函数时,不用担心自己定义的函数,是否会与其他文件中的函数同名,因为你编写的函数只是在你的模块或文件中可见
static void FuncA()
3.静态成员变量/函数
(1)静态成员变量:在类内数据成员的声明前加上关键字static,该数据成员就是类的静态数据成员了
class CSaving
{
private:
static double m_dInterstRate;
};
double CSaving::m_dInterstRate = 0.05;
static成员变量的特点:
1.静态数据成员和普通数据成员一样遵从public,private,protected访问规则
2.静态数据成员的初始化的格式为:<数据类型><类名>::<静态数据成员名>=<值>
3.修改一个对象中的静态变量,另外一个对象的静态变量也会被修改,所以无论这个类的对象被定义了多少个,静态数据成员在程序中只有一份拷贝,由该类型的所有对象共享访问,即静态成员变量属于类所有,不属于类的实例所有。也就是说即使一个类没有定义任何实例,类中的静态成员也是存在的,也可以正常使用它
静态数据成员存储在全局数据区,静态数据成员定义时要分配空间,所以不能在类声明中定义。另外,类的静态数据成员不占用类的存储大小
与全局变量相比,静态数据成员没有进入程序的全局名字空间,因此不会存在与程序中其他全局名字冲突的可能性。另外,将静态变量声明为private成员可以实现数据信息的隐藏,而全局变量则无法实现
(2)静态成员函数
静态成员函数和静态成员变量一样,它为类的服务而不是为类的具体对象服务。这里需要说明的是:一般普通成员函数都隐含一个this指针(this指针指向类的对象本身),而静态成员函数不存在this指针,因为静态成员函数不属于任何对象,它属于类。因此,静态成员函数无法访问类对象的非静态成员(包含非静态数据成员和非静态成员函数),它只能调用静态成员函数。
因为静态成员函数也属于类的成员函数,所以可以采用访问操作符"."和"->"进行静态成员函数的调用。同样,由于静态成员函数属于类,也可采用下述格式进行静态成员函数的调用
<类名>::<静态成员函数名>(<参数表>)
特点:
1.静态成员可以访问静态成员,但绝对不能访问非静态成员。这是因为静态成员在类定义时便产生和分配空间了,而非静态成员只是在类定义时才会产生并分配空间,所以当静态成员操作非静态成员时一般会报出“访问未定义变量”错误
2.静态成员随着程序的开始运行而产生,而后便一直存在不会消失,只有当程序执行完毕退出后才会释放空间并消失,所以静态成员函数不能在任何函数内分配空间和初始化
3.静态成员不能声明为虚函数。这是因为静态成员函数在对象实例未生成前便可以调用。而如果对象实例未产生,虚函数调用使用的虚函数表未生成,导致虚函数调用时不知调用子类的虚函数还是父类的虚函数
4.非静态成员函数可以任意访问静态成员函数,而静态成员函数只能访问静态成员函数
三.const
const可以说是C++中最为神奇的关键字。它的神奇之处在于:可以通过编译器指定语义上的约束,而不需要花费任何的代价。const的用途多样。例如,在类的外部,可以定义全局作用域的常量,也可以通过添加static来定义文件,函数或程序块作用域的常量。对于指针,通过const可以定义指针是const,其所指向的数据是const或两者都是const
char szGreeting[] = "Hello,world";
char* pszGreeting = "szGreeting"; //非const指针,非const数据
const char* pszGreeting = szGreeting; //非const指针,const数据
char* const pszGreeting = szGreeting; //const指针,非const数据
const char* const pszGreeting = szGreeting; //const指针,const数据
规律如下:
如果const在*的左边,说明指针所指向的对象是常值;如果所指向的对象为常值,const在类型的前面和后面都一样。如果const在*的右边,说明指针是恒值。
最复杂的是const同时出现在*的左右两侧,此时说明指针是恒值,指针所指向的对象也是恒值。
1.函数返回值声明为const
让函数返回一个常量值,经常可以在不降低安全性和效率的前提下减少用户出错的概率。请看以下片段
CRational{} //有理数类,支持有理数的加减乘除四则运算
CRational operator*(const rational& lhs,const rational& rhs); //有理数乘法运算
CRational a,b,c;
(a*b)=c; //对a*b的结果赋值,不符合逻辑,但可以通过编译
修改如下
CRational{} //有理数类,支持有理数的加减乘除四则运算
const CRational operator*(const rational& lhs,const rational& rhs); //有理数乘法运算
CRational a,b,c;
(a*b)=c; //对a*b的结果赋值,编译器报出编译错误
声明operator*操作符重载函数的返回值为const可以避免对两个数的运算结果赋值问题。对程序员来说,对两个数的运算结果赋值是非常没有道理的。
2.const成员函数
函数具有const属性,这是C++所特有的特征。将成员函数声明为const就是指明这个函数可以被const对象调用
const成员函数的优点
const成员函数可使得类的接口更加容易理解
const成员函数可以与const对象协同工作。这是高效编码十分重要的一个方面
如果成员函数之间的区别仅仅为"是否是const的",那么它们可被重载。很多人忽略这点
当且仅当一个成员函数对所有的数据成员都不做出改动时,才需要将此函数声明为const。也就是说如果一个成员函数声明const的条件是:成员函数不对对象内部做任何修改。它使得错误检查变得更轻松。
3.尽量用const常量替换#define常量定义
在C语言中定义一个int型常量,必须这样定义
#define MAX_LENGTH 100
而C++大可不必,因为这种实现存在很多陷阱。如#define只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意想不到的错误
通过const实现常量定义。const int MAX_LENGTH = 100
从汇编的角度来看const定义常量,只是给出了对应的内存地址,而不是像#define一样给出的是立即数。const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝,所以使用const常量可以节省内存。所以尽量用const常量替换#define常量定义
typedef,static,const用法的更多相关文章
- const和typedef的常见用法详解
一.说说const 一般而言,const主要是用来防止定义的对象再次被修改,定义对象变量时要初始化变量. 常见用法如下: 1.用于定义常量变量,这样这个变量在后面就不可以再被修改 const int ...
- static 与单例模式、auto_ptr与单例模式、const 用法小结、mutable修饰符
一.static 与单例模式 单例模式也就是简单的一种设计模式,它需要: 保证一个类只有一个实例,并提供一个全局访问点 禁止拷贝 C++ Code 1 2 3 4 5 6 7 8 9 10 11 ...
- C语言关键字—-sizeof 、typedef、const、static、register、extern、#define
关键字:sizeof .#define.typedef.const.static.register.extern sizeof 1. 作用:求数据所占得内存空间大小 2. 本质:求数据得类型所占的内存 ...
- 关于竞赛大佬常用的 static const auto _ = []() 用法解析
前言 在刷Leetcode的时候发现很多运算速度极快的代码都有这一段,所以研究一下. static const auto _ = []() { ios::sync_with_stdio(false); ...
- c++ const用法小结
const用法 1,定义全局变量的内存分配问题 #define Pi_1 3.14 //使用#define宏 const double Pi_2 = 3.14 //使用const ...
- C++的那些事:const用法面面观
一.const是什么 在 C/C++ 语言中,const关键字是一种修饰符.所谓“修饰符”,就是在编译器进行编译的过程中,给编译器一些“要求”或“提示”,但修饰符本身,并不产生任何实际代码.就 con ...
- C++ static、const和static const 以及它们的初始化
转自C++ static.const和static const 以及它们的初始化 const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间. s ...
- static const readonly
C#中的static 和Java中的static 简单,两者用法完全是一致的.从两方面讨论: 1. 变量是属于类的,不是实例级别的.只能通过类名调用,不能通过实例调用. 2. 如果在定义时就赋值了,那 ...
- 【转】话说C语言const用法
原文:话说C语言const用法 const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,意即其所修饰的对象为常量(immutable). 我们来分情况看语法上它该如何被使用. 1.函数体内修 ...
随机推荐
- BZOJ 1143 [CTSC2008]祭祀river(二分图匹配)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1143 [题目大意] 给出一张有向图,问最大不连通点集,连通具有传递性 [题解] 我们将 ...
- oracle字符集查看修改
一.什么是Oracle字符集 Oracle字符集是一个字节数据的解释的符号集合,有大小之分,有相互的包容关系.ORACLE 支持国家语言的体系结构允许你使用本地化语言来存储,处理,检索数据.它使数据库 ...
- configure mount nfs
qemu-img convert -f raw -O qcow2 nix.img ruiynix.qcow2 1,yum createrepo
- oracle传输表空间功能测试(含详细过程)
最近做数据迁移,之前有一篇迁移思路思考的文章,这里继续做具体的测试,主题问表空间传输. 一.源服务器上导出表空间 源服务器: 10.1.122.55 目标服务器:10.1.122.54 0.设置字 ...
- xcode UIImageView创建、图片加载、 音频文件播放、 延迟调用
代码创建 /** 创建UIImageView */ UIImageView * imageView=[[UIImageView alloc]init]; /** 设置尺寸位置 */ imageView ...
- mockjax MOCK.js的拦截ajax请求
今天看了下 mock.js的拦截请求 .https://github.com/nuysoft/Mock/blob/master/src/mockjax.js //覆盖(拦截) Ajax 请求,目前内置 ...
- Unity5UGUI 官方教程学习笔记(一)Canvas
Canvas Canvas是控制一组UI元素将被渲染 所有的UI元素必须是Canvas下的子物体 一个场景中可以拥有多个Canvas 在创建UI元素时,如果没有Canvas,将会自动创建Canvas ...
- 多关键字排序(里面有关于操作符(<<运算符 和 >>运算符 )的重载)
一种排序 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复:还知道这个长方形的宽和长,编号.长.宽都是整数:现 ...
- Java 动态代理(转)
一.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后 处理消息等.代理类与委托类之间通常会存在 ...
- VC++学习之GDI概述
VC++学习之GDI概述 图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏 ...