内存分区:
1、代码区(存放程序代码)
2、数据区(存放程序编译和执行过程中出现的变量和常量)
a、静态区 b、堆区 c、栈区 d、常量区
内存分配问题通常分为:静态内存、栈内存、堆内存(又叫自由空间)
静态内存/栈内存:由编译器自动创建和销毁
堆:存储动态分配的对象(程序运行时分配),需要程序员手动(显示)销毁。
静态内存:
static定义的变量最终只会分配一次内存,如果再次调用该函数,不会重新分配内存给变量,而是使用上次分配的内存
1、局部静态对象
局部对象:形参和函数体内部定义的变量
(仅在函数的作用域可见,同时局部变量会隐藏在外层作用域中同名的其他声明中)
自动对象:只存在于块运行期间的对象
(对于普通局部变量对应的对象来说,当函数的控制路径经过变量定义语句时创建该对象,到达定义所在块末尾时销毁)
局部静态对象:在程序的执行路径第一次经过对象定义语句时初始化,直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。
void func()
{
static int a; //局部static对象
}
2、类的静态数据成员
a、与类本身直接有关,而不是与类的各个对象保持关联
b、可以是public或private,类型可以是常量、引用、指针、类类型等
c、存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据
d、不与任何对象绑定,不包含this指针
e、静态成员函数不能声明为const,不能在static函数体内使用this指针
f、通过作用域运算符(::)、类的对象、引用或者指针访问(成员函数不用通过作用域运算符就能直接使用静态成员)
g、可以在类的内部或类的外部定义静态成员函数,但外部定义时不能重复static关键字,static只出现在类内部声明语句中
h、不属于类的任何一个对象,不能在类的内部初始化静态成员,必须在类的外部定义和初始化,且只能定义一次
class Account
{
public:
Account(string m_owner,double m_amount)
{
owner=m_owner;
amount= m_amount ;
}
void calculate()
{
amount += amount*interestRate;
cout << "账户" << amount << endl;
}
static double rate()
{
return interestRate;
}
static void rate(double);
private:
string owner;
double amount;
static double interestRate; //所有Account所共享
};
void Account::rate(double newRate) //定义静态成员函数
{
interestRate = newRate; //更新利率
}
double Account::interestRate = 1.13; //定义并初始化一个静态成员 原始利率
int main()
{
double r;
Account a1("小王", 0105); //类的实例化
r = a1.rate(); //通过Account的对象或引用 (原始利率)
cout << "初始利率" << r<<endl;
Account::rate(1.25); //使用作用域运算符访问静态成员 (更新利率)
cout << "现在利率" << a1.rate()<< endl;
a1.calculate();
Account *a2 = &a1;
r = a2->rate(); //通过指向Account对象的指针
}
程序结果输出:
初始利率1.13
现在利率1.25
账户155.25
3、定义在任何函数之外的变量
static作用:
- 修饰普通变量,修改变量的存储区域和生命周期,使变量存储在静态区,在 main 函数运行前就分配了空间,如果有初始值就用初始值初始化它,如果没有初始值系统用默认值初始化它。
- 修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命名空间里的函数重名,可以将函数定位为 static。
- 修饰成员变量,修饰成员变量使所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员。
- 修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在 static 函数内不能访问非静态成员。