0
点赞
收藏
分享

微信扫一扫

(P17)对象的使用:static成员,static成员函数小结,四种对象的作用域与生存期


文章目录

  • ​​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)一些常量存放在代码段中

(P17)对象的使用:static成员,static成员函数小结,四种对象的作用域与生存期_Test

  • 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;
这样会造成重定义的问题


举报

相关推荐

0 条评论