C++之const和static的区别
const定义的常量在超出其作⽤域之后其空间会被释放,⽽static定义的静态常量在函数执⾏后不会释放其存储空间。
static表⽰的是静态的。类的静态成员函数、静态成员变量是和类相关的,⽽不是和类的具体对象相关的。即使没有具体对象,也能调⽤类的静态成员函数和成员变量。⼀般类的静态函数⼏乎就是⼀个全局函数,只不过它的作⽤域限于包含它的⽂件中。
在C++中,static静态成员变量不能在类的内部初始化。在类的内部只是声明,定义必须在类定义体的外部,通常在类的实现⽂件中初始化,如:double Account::Rate=2.25;static关键字只能⽤于类定义体内部的声明中,定义时不能标⽰为static
在C++中,const成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进⾏,并且必须有构造函数。
const数据成员 只在某个对象⽣存期内是常量,⽽对于整个类⽽⾔却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类的声明中初始化const数据成员,因为类的对象没被创建时,编译器不知道const数据成员的值是什么。
const数据成员的初始化只能在类的构造函数的初始化列表中进⾏。要想建⽴在整个类中都恒定的常量,应该⽤类中的枚举常量来实现,或者static cosnt。
class Test
{
public:
Test():a(0){}
enum {size1=100,size2=200};
private:
const int a;//只能在构造函数初始化列表中初始化
static int b;//在类的实现⽂件中定义并初始化
const static int c;//与 static const int c;相同。
};
static修饰的变量int Test::b=0;//static成员变量不能在构造函数初始化列表中初始化,因为它不属于某个对象。
cosnt int Test::c=0;//注意:给静态成员变量赋值时,不需要加static修饰符。但要加cosnt
static关键字:
经过static修饰的变量会作为类的属性⽽不是实体属性存在。
static修饰的变量作为程序运⾏时的静态变量,存在于内存的静态区,静态区的数据初始化⼯作由操作系统在加载完程序后执⾏main函数前进⾏。操作系统在加载完程序后,将常量区中存放的变量初值复制给静态变量,完成其初始化。
static修饰的变量通过int ClassName::value=1这种⽅式进⾏初始化。此时不再需要static 关键字。程序运⾏期间也可以对变量进⾏赋值操作。
const关键字:
经过const修饰的属性,顾名思义是指常量。
const修饰的属性仍然属于实体属性,所以其初始化⼯作,需要由构造函数的初始化列表中完成。⽽且
也只能在构造函数的初始化列表中初始化,运⾏期间将不能再对const属性进⾏修改。值得注意的是,虽然经过const修饰,但是因为变量属于实体属性,⽽实体对象存在于动态区,所以const属性也属于动态区,所以可以通过取址直接操作指向的内存的值,以绕过编译器对其只读的限制检查。
static const关键字:
static const 和 const static 含义相同。
static const有两种⽤法,⼀种是作为预编译声明,⼀种是作为类的静态常量属性。
当作为预编译声明时,static const 属性必须在声明时即指定值,⽽且类型仅限基本数据类型,保证了程序的健壮性。
const static常量存在于内存的常量区,有操作系统加载程序时,加载到内存的常量区。所以可以对其取址,但是不能对该区的内存进⾏写操作,因为这个区从操作系统级进⾏了只读限定,任何对该内存区的写操作会导致程序崩溃。
总结:
static const 和const的区别是:
const声明的只读变量,在程序运⾏期间不能对其进⾏写操作,写操作将⽆法通过编译,也就是说它是通过编译器控制的只读,所以如果想下⾯这样:
A a;
int * pa = (int*)&a.a;
*pa = 2;
则可以绕过编译器修改他的值。
但是 static const属性虽然也可以取址,但是对其写操作将会导致程序崩溃。因为static const 存在于常量区,⽽const存在于动态区。
static const 和 static的区别是:
static 存在于静态区,该区可以进⾏写操作,其初始化的值也会存在常量区,程序启动后由操作系统从常量区取值赋值给static变量。
——————————————————————————————————————————————————————
引⽤作为函数返回值:
int& func() {
int q;
//! return q; // 在编译时发⽣错误
static int x;
return x; // 安全,x 在函数作⽤域外依然是有效的
}
引⽤作为函数参数:
#include <iostream>
using namespace std;
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues( int i )
{
return vals[i]; // 返回第 i 个元素的引⽤
}
// 要调⽤上⾯定义函数的主函数
int main ()
{
setValues(1) = 20.23; // 改变第 2 个元素
setValues(3) = 70.8; // 改变第 4 个元素
}
(1)以引⽤返回函数值,定义函数时需要在函数名前加 &
(2)⽤引⽤返回⼀个函数值的最⼤好处是,在内存中不产⽣被返回值的副本。
引⽤作为返回值,必须遵守以下规则:
(1)不能返回局部变量的引⽤。主要原因是局部变量会在函数返回后被销毁,因此被返回的引⽤就成为了"⽆所指"的引⽤,程序会进⼊未知状态。
(2)不能返回函数内部new分配的内存的引⽤。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引⽤),⼜⾯临其它尴尬局⾯。例如,被函数返回的引⽤只是作为⼀ 个临时变量出现,⽽没有被赋予⼀个实际的变量,那么这个引⽤所指向的空间(由new分配)就⽆法释放,造成memory leak。
(3)可以返回类成员的引⽤,但最好是const。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在⼀个业务规则当中。如果其它对象可以获得该属性的⾮常
量引⽤(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论