===============static关键字=======================
主要有4个使用场景:
1、修饰类的成员变量和成员方法(常用):
被修饰的成员属于类,不属于单个类对象,为所有类对象所共享。
并且建议通过类名调用。被修饰的成员变量与方法存放在静态存储区。
2、 函数内的静态变量:
其作用范围为函数内,其生命期为整个程序生命期。
这样可以保证多次调用中其值一直得以保存。
该变量在内存中只被分配一次。
3、模块内的静态全局变量:(还可以是静态函数)
可以被模块内所用的函数访问,不能被其他模块的函数访问。(在其他模块中使用需要使用 using namespace);
全局变量本身是静态存储的,静态全局变量也是静态存储的。
但是非静态全局变量的作用域是整个程序(一个源程序由多个源文件组成),非静态全局变量在所有源文件中都是有效的。
静态全局变量则限制了其作用域,只在定义该变量的源文件内有效,同一程序的其他源文件不能使用它。
这样做的好处是,可以避免其他源文件的引用而引起错误。
static起初是为了表示退出一个块后仍然存在的局部变量。
后来又有了第二种含义,用来表示不能被其他文件访问的全局变量和函数。
这是为了避免引入新的关键字,所以仍使用static关键字来表示这第二种含义。
static类成员
C++ static类成员,:https://www.cnblogs.com/fuqia/p/8888938.html
C++primer里面说过,static类成员不像普通的类数据成员,static类数据成员独立于一切类对象处在。static类数据成员是与类关联的,
但不与该类定义的对象有任何关系。
static类成员必须要在类外进行初始化;
用static修饰的成员变量在对象中是不占内存的,因为他不是跟对象一起在堆或者栈中生成,用static修饰的变量在静态存储区生成的。所以用static修饰一方面的好处
由于static修饰的类成员属于类,不属于对象,因此static类成员函数是没有this指针的,this指针是指向本对象的指针。正因为没有this指针,所以static类成员函数
不能访问非static的类成员,只能访问 static修饰的类成员。
C++中static关键字作用总结:https://www.cnblogs.com/songdanzju/p/7422380.html
静态数据成员在<定义或说明>时前面加关键字static。
静态数据成员是静态存储的,所以必须对它进行初始化。
有关静态成员变量、静态成员函数的详细描述: https://blog.csdn.net/lms1008611/article/details/81408236
类的成员函数有如下特性:
-静态成员函数是类的一个特殊的成员函数
-静态成员函数属于整个类所有,没有this指针
-静态成员函数只能直接访问静态成员变量和静态成员函数
-可以通过类名直接访问类的公有静态成员函数
-可以通过对象名访问类的公有静态成员函数
-定义静态成员函数,直接使用static关键字修饰即可
静态成员函数在C++中的作用很强大
-静态成员变量属于整个类所有
-静态成员变量的生命期不依赖于任何对象,为程序的生命周期
-可以通过类名直接访问公有静态成员变量
-所有对象共享类的静态成员变量
-可以通过对象名访问公有静态成员变量
-静态成员变量需要在类外单独分配空间
-静态成员变量在程序内部位于全局数据区 (Type className::VarName = value)
.
=================================================
sizeof :是关键字不是函数
extern :置于变量和函数前,以表示变量或者函数的定义在别的文件中。https://www.cnblogs.com/Lunais/p/5991135.html
volatile:用于告知编译器其修饰的变量随时可能发生变化,每次使用它是必须从内存中重新取出。
=================================================
struct关键字
将一些相关联的数据打包成一个整体,方便使用。
结构体所占空间大小是其成员所占内存之和。
但是结构体
struct student{
}stu;
sizeof(stu)的值是多少?不是0,而是1。
因为编译器认为任何数据类型都有其大小。
在上面的声明中,第一个和第二声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的,如果令t3=&s1,则是非法的。
结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
参考链接:https://blog.csdn.net/wekic/article/details/73107387
结构体的定义如下所示,struct为结构体关键字,tag为结构体的标志(结构体的名字),member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量。
struct tag { member-list } variable-list ;
struct和class关键字区别:
一般两者可以通用,但是有一个很小的区别,就是struct成员默认是public的,而class成员可以是private的。
1 //此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c 2 //同时又声明了结构体变量s1 3 //这个结构体并没有标明其标签 4 struct 5 { 6 int a; 7 char b; 8 double c; 9 } s1; 10 11 //此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c 12 //结构体的标签被命名为SIMPLE,没有声明变量 13 struct SIMPLE 14 { 15 int a; 16 char b; 17 double c; 18 }; 19 //用SIMPLE标签的结构体,另外声明了变量t1、t2、t3 20 struct SIMPLE t1, t2[20], *t3; 21 22 //也可以用typedef创建新类型 23 typedef struct 24 { 25 int a; 26 char b; 27 double c; 28 } Simple2; 29 //现在可以用Simple2作为类型声明新的结构体变量 30 Simple2 u1, u2[20], *u3;
struct和union关键字区别:
union维护足够多的空间来存放多个数据成员中的“一种”。而不是为每一个数据成员配置空间。
在union中所有的数据成员共用一个空间。同一时间只能存储其中一个数据成员。
所有的数据成员具有相同的起始位置。
对union成员的存取都是从联合体基地址的偏移量为0处开始的。
也就是说联合体的访问不论对哪个变量的存取都是从union的首地址位置开始的。
另外我们还可以使用union来判断当前系统是大端存储还是小端存储:
int checkSystem()
{
union check{
int i;
char ch;
}c;
c.i = 1;
return(c.ch == 1);
}
利用union数据类型的特点,所有成员的起始地址一样。
如果true,则ch是1,则说明是小端法;
如果false,则ch是0,则说明是大端法;
至于什么是大小端,可以查看我之前的文章:
何为大小端:https://www.cnblogs.com/grooovvve/p/10710270.html
在实际项目中,结构体是大量存在的。研发人员常使用结构体来封装一些属性来组成新的类型;
结构体在函数中的作用不是简便,其最主要的作用就是封装。封装的好处就是可以再次利用。
让使用者不必关心这个是什么,只要根据定义使用就可以了。
struct和typedef区别:
typedef本身是用来定义类型别名的;给已经存在的数据类型重命名;
而struct是定义一个新的数据类型;将一些数据封装成一个整体;
================================================
enum关键字
enum枚举与#define宏的区别
#define宏一次只能定义一个,而且不能调试,其原理只是在预编译阶段进行简单的替换而已;
enum一次可以定义大量相关的常量,可以调试,枚举常量是在编译时候确定其值的;
enum关键字表示了一种数据类型,枚举类型;
在实际问题中,有些变量的取值被限定在一个有限的范围内;
为此,C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,
被说明为该“枚举”类型的变量取值不能超过定义的范围。
enum weekday{sun,mon,tue,wed,thu,fri,sat};
然后就可以定义枚举类型变量:enum weekday day;
如果觉得这样比较麻烦,就可以用typedef继续简化一下,定义类型别名;
================================================
typedef关键字
简单来讲就是可以给已经存在数据类型重新取名字;很常用的情况就是给结构体重新取名;
当需要抽象的时候,用typedef比较好,即只需要关注一个抽象的类型,而不是在意这个类型是基于struct或者什么来的。
typedef本身是用来定义类型别名的,而不是为了简化struct的使用的;
================================================
const关键字
指针常量:char * const p; //const修饰的是指针p。是一个常量,指针常量
常量指针:const char * p; //是一个指针,指向常量的指针
const,被const修饰的东西都收到强制保护;
const一般用来修饰函数的输入参数;
如果采用值传递,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护。所以不需要加const修饰。
对于非内部数据类型的参数而言,像void Func(A a);这样声明的函数注定效率比较低。
因为需要产生A类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。
所以如果函数不去改变对象A,而只是读取的话,可以将函数声明为void Func(const A &a);
但是引用传递有可能改变a,这是需要小心的;
对于内部类型的输入参数,“值传递”和“const 引用传递”,这两种方式的效率是相当的。
如果const修饰函数额返回值:
如果以指针传递方式
const char * GetString(void);
那么下面语句将会出现编译错误:char *str = GetString();
正确的用法应该为:const char * str = GetString();
如果返回值采用值传递,因为函数会把返回值复制到外部临时的存储单元,所以加const修饰没有任何价值;
返回值采用“引用传递”的方式不多,这种方式一般出现在类的赋值函数中。目的是为了实现链式表达。
class A{
A & operate = (const A &other); //赋值函数
};
A a,b,c;
a=b=c; //正常的链式赋值
const成员函数,任何不会修改数据成员的函数都应该声明为const类型;
如果在编写const成员函数的时候,不慎修改了数据成员,或者调用了其他非const成员函数,编译器将指出错误,这会提高程序的健壮性;
class Stack{
public:
int GetCount(void) const; //这里看起来比较奇怪,const关键字只能放在函数声明的尾部。
};
https://blog.csdn.net/xixihaha331/article/details/51280263
原文链接: https://www.cnblogs.com/grooovvve/p/12381090.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/332406
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!