目录
C++的五大内存区
C++程序的内存格局通常分为五个区:全局数据区(data area),代码区(code area),栈区(stack area),堆区(heap area)(即自由存储区),常量区。
全局数据区(静态区):存放全局变量,静态数据和常量;
代码区:存放所有类成员函数和非成员函数代码,函数体的二进制代码。
栈区:存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
堆区:new、malloc、realloc分配的内存块,一般编译器不会释放内存,需要用程序释放,内存泄露通常说的就是堆区。
常量区:存放常量的,不允许修改,比如常量字符串存放在这。
静态成员变量,成员函数和普通成员变量,成员函数的内存分配
静态成员变量:存储在全局数据区,所以也叫对象的共享数据
静态成员函数:内存的代码区,是属于类而非属于对象的,不占用对象的存储空间
普通成员变量:随着对象的建立而分配内存,不同的对象存储在不同的区里,全局对象和静态局部对象即存放在全局数据区,局部对象存放在栈区中,动态对象存放在堆区中
普通成员函数:存放在代码区,是属于类的,不占用对象的存储空间
如图1.1
静态成员变量与函数
生命周期
静态成员变量的生命周期是整个程序,作用域在类内,而静态变量的生命周期是整个程序,作用域在函数体内,当它的值第一次被调用后,其值会维持不变,下一次运算仍然是第一次被调用后计算的值。
定义
静态成员变量要在类内声明,类外初始化,且必须初始化。
class Maker
{
public:
Maker()
{
//a = 20;
}
public:
static int a;
};
初始化代码:
int Maker::a = 100;
静态成员变量属于类不属于对象
静态成员变量属于类不属于对象,是所有对象共享,十个对象也只有一个变量,节省空间时间。原因:静态成员变量存储在全局数据区和普通成员变量存储在同一个区域里面,所有对象共享其内容,所以你在一个对象里修改了静态成员变量的内容,当其他函数调用这个变量时,仍然是上一个对象修改的值,但是,这并不意味着,静态成员变量和普通成员函数存储在同一个位置里如图1.1,如图1.2对象对类内函数的调用:
图1.2
静态成员变量(函数)可以用类访问,也可以用对象访问
用类访问:
Maker::a=100;
Maker::get();
用对象访问:
Maker m;
m.a;
m.get();
静态成员函数只能访问静态成员变量
静态成员函数只能访问静态成员变量,但普通成员函数却能访问所有变量包括静态成员变量,因为:静态成员函数没有传入this指针,this指针详解在下方。
const修饰的静态成员变量要在类内初始化
const修饰的静态成员变量最好在类内初始化,虽然类外也可以初试化
class Maker4
{
public:
const static int a=20;
const static int b;
};
//类外也可以初始化
const int Maker4::b = 30;
静态成员函数也有权限
静态成员函数也有权限,如果为私有,类外不可以访问,而静态成员变量即便你为私有,在类外仍然可以访问
class Maker3
{
private:
static void func()
{
cout << "a3=" << a3 << endl;
}
private:
static int a3;
};
this指针
作用
1.当形参和成员变量名相同时,用this区分
class Maker2
{
public:
int id;
static int a;
public:
//1.当形参和成员变量名相同时,用this区分
Maker2(int id)
{
this->id = id;
}
}
int Maker2::a = 10;
2.返回对象的本身
class Maker2
{
public:
int id;
static int a;
public:
//2.返回对象的本身
Maker2 &getMaker2()
{
return *this;//赋值运算符重载的时候有用,详情见运算符重载
}
};
int Maker2::a = 10;
this指针指向的是对象的成员空间
this指针指向的是对象的成员空间,所以this指针并不能指向静态成员变量
如图1.3
this指针的指向不能被改变
this指针的指向不能被改变,this指针实质是这样:
Maker *const this;
每个普通成员函数都传入了this指针
每个普通成员函数编译器都传入了this指针,这也解释了当很多对象共享同一个普通成员函数时,函数是怎么分辨是哪个对象的,就是靠this指针。(静态成员函数并没有传入this指针,所以它只能访问静态成员变量)
指针不占用对象空间
指针并不是对象的一部分,不会占用对象的空间,能占用对象空间的只有普通成员变量(看图也能知道)。
常函数
定义
在函数()后面加上const
class Maker
{
public:
//1.在函数()后面加上const
void printMaker()const
{......}
public:
int id;
int age;
};
常函数内不能修改普通成员变量
class Maker
{
public:
void printMaker()const
{
//id = 100;err//2.常函数内不能修改普通成员变量
}
public:
int id;
int age;
};
常函数里const修饰this
const修饰的是this指针指向的空间,其中的变量不能改变
这是没加const的this指针Maker *const this;
这是加了const的this指针const Maker *const this;//这是常函数修饰的
mutable修饰成员变量
mutable修饰的成员变量在常函数中可以修改
class Maker
{
public:
Maker(int id, int age)
{
this->id = id;
this->age = age;
score = 100;
}
void printMaker()const
{
score=200;
}
public:
int id;
int age;
mutable int score;//4.mutable修饰的成员变量在常函数中可以修改
};
常对象
定义
在数据类型前面加上const,让对象称为常对象,常对象被定义后其值就不能再被修改。
const Maker m(1, 18);
注意
- 常对象不能改变普通成员变量的值
- 常对象不能调用普通成员函数,因为普通成员函数有可能存在修改普通成员变量的语句
- 常对象只能调用常函数
- 常对象只能修改mutable修饰的成员变量