文章目录
- 1.static成员,static成员函数小结
- 2.四种对象作用域与生存期
- 3.static用法总结
1.static成员,static成员函数小结
- static成员独立于类对象而存在,也就是说它不属于某个对象的成员,它不能被全体对象所共享
- 统计类类型对象创建的个数,用static成员来实现
- 非static成员它属于类对象,每个对象都有一份拷贝
- static成员函数访问方式:通过类名,eg:A::statusFunc()来访问的,所以没有传递this指针,因而不能访问非static成员(因为非static属于某个对象,需要通过this指针来引用),也不能调用非static成员函数
- 对象的作用域与生存期不等同
(1)作用域指的是该变量可见的范围
(2) 在堆上创建的对象,没有调用delete的话,该对象就不会被释放,也就是他的生存期还是存在的
(3)栈上对象的作用域与生存期是等同的 - eg:static成员函数的用法
17cpp\17cpp\17cpp\01.cpp
#include <iostream>
using namespace std;
class Date
{
public:
Date(int year) : year_(year)
{
}
//判断年份是否是闰年
static bool IsLeapYear(int year)
{
return (year % 4 == 0 && year % 100 != 0) || (year % 400 ==0);
}
bool IsLeapYear()
{
return (year_ % 4 == 0 && year_ % 100 != 0) || (year_ % 400 ==0);
}
private:
int year_;
};
int main(void)
{
Date d(2012);
cout<<d.IsLeapYear()<<endl;
//使用静态成员函数,不需要创建一个日期对象,就能访问,就能直接判断该日期是否是闰年
cout<<Date::IsLeapYear(2010)<<endl;
return 0;
}
- 测试:
2.四种对象作用域与生存期
- 栈对象
隐含调用构造函数(程序中没有显示调用),是自动释放的 - 堆对象
隐含调用构造函数(程序中没有显示调用),但是没有显示释放 - 全局对象、静态全局对象
全局对象的构造先于main函数
已初始化的全局变量或静态全局对象存储于.data段中
未初始化的全局变量或静态全局对象存储于.bss段中 - 静态局部对象
已初始化的静态局部变量存储于.data段中
未初始化的静态局部变量存储于.bss段中 - 内存布局如下:
(1).bss段和.data端区别:
.bss段特点:在可执行文件中不占用空间,因为变量的初始值为0,只需要符号即可,在程序加载的时候才分配了这样的一个段
.data段在可执行文件中是占用空间的
(2)一些常量存放在代码段中
- eg:17cpp\17cpp\17cpp\02.cpp
#include <iostream>
using namespace std;
class Test
{
public:
Test(int n) : n_(n)
{
cout<<"Test "<<n_<<" ..."<<endl;
}
~Test()
{
cout<<"~Test "<<n_<<" ..."<<endl;
}
private:
int n_;
};
int n; // 未初始化的全局变量,初始值为0。n存储于.bss段中。(bss含义:block started by symbol)
int n2 = 100; // 已初始化的全局变量,初始值为100。n2存储于.data段中。
Test g(100); // 全局对象的构造先于main函数
static Test g2(200); //静态全局对象的构造也先于main函数
int main(void)
{
cout<<"Entering main ..."<<endl;
cout<<n<<endl;
//作用域在main的括号之内(块作用域)
Test t(10); // 栈上创建的对象,在生存期结束的时候自动释放
{
Test t(20);
}
{
Test* t3 = new Test(30); // 堆上创建的对象,要显示释放
delete t3;
}
{
//注意局部静态类对象和局部静态变量的区别
static int n3; // n3存储于.bss段中 (在编译期初始化,在编译的时候就会分配空间)
static int n4 = 100; // n4存储于.data段中 (在编译期初始化,在编译的时候就会分配空间)
//t4对象的作用域范围是在块作用域范围内,但是生存期是在整个程序范围之内
static Test t4(333); // t4对象在运行期初始化,存储于.data段
}
cout<<"Exiting main ..."<<endl;
}
- 测试:
static Test t4(333);是在第一次运行的时候初始化的
3.static用法总结
- (1)用于函数内部修饰变量,即函数内的静态变量。这种变量的生存期长于该函数,使得函数具有一定的“状态”。使用静态变量的函数一般是不可重入的,也不是线程安全的,比如strtok(3)。
- (2) 用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数。专业的说法叫“具有internal linkage”(简言之:不暴露给别的translation unit编译单元)。
C语言的这两种用法很明确,一般也不容易混淆。 - 由于C++引入了类,在保持与C语言兼容的同时,static关键字又有了两种新用法:
- (3)用于修饰类的数据成员,即所谓“静态成员”。
这种数据成员的生存期大于class的对象(实例/instance)。
静态数据成员是每个class有一份,普通数据成员是每个instance 有一份。 - (4) 用于修饰class的成员函数,即所谓“静态成员函数”。
这种成员函数只能访问静态成员和其他静态成员函数,不能访问非静态成员和非静态成员函数 - 对上述static用法总结中(1)的具体说明
当程序执行出了该函数之后,该变量还是存在的;
第一次进来的时候初始化,第二次进来的时候不会为该变量分配空间了;
如果n的值该为200,那么下一次用到该函数的时候,变量n不再分配空间,第二次进来的时候n的值已经成了200
这种函数是有状态的,称之为不可重入的函数,也是线程不安全的,不会用在信号处理函数中
void foo()
{
static int n = 100;
n = 200;
}
- 对上述static用法总结中(2)的具体说明
下面这样定义是可以的
a.c看不到b.c中的n变量
a.c文件中
static int n = 100;
b.c文件中
static int n = 100; internal linkage,对其他编译单元不可见
这两个变量是2个独立的空间
================================
如果要共享同一个变量
a.c文件中
int n = 100; external linkage,对其他编译单元可见
b.c文件中 b.c访问的变量和a.c访问的变量是同一个变量,也就是所谓的全局变量(全局变量要在.c文件中定义)
extern int n; 也可以将extern int n放文件b.c中的头文件中,相当于外部声明了
==============================
错误用法,会造成重定义的问题:
x.h
在x.h文件中定义全局变量
int n = 100;
a.c 包含x.h头文件后,相当于定义了int n = 100;
b.c 包含x.h头文件后,,相当于定义了int n = 100;
这样会造成重定义的问题