一、标识符的作用域与可见性:
1>.作用域:
指的是标识符的有效范围,一个标识符在程序正文中有效的区域;
c++作用域:
(1)函数原型作用域(C++程序中最小的作用域)
(2)局部作用域(块作用域)
函数形参列表中形参的作用域,从形参列表中的声名处开始,到整个函数体结束处为止;函数体内声明的变量,其作用域从声明开始,直到声明所在的块结束的大括号为止。
(3)类作用域
类:一组有名成员的集合,类X的成员m具有类作用域,对m的访问方式有3种:
1)如果在X的成员函数中没有声明同名的局部作用域标识符,那么在该函数内可以直接访问成员m。
2)通过表达式x.m或者X::m。这正是程序中访问对象成员的最基本的方法。
X::m用于访问类的静态成员。
3)通过ptr->m这样的表达式,其中ptr为指向X类的一个对象的指针。
(4)命名空间作用域(文件作用域) c++标准程序库的所有标识符都被声明在 std 命名空间中,该空间的变量也称为: 全局变量
例1:
#include<iostream>
using namespace std;
int i; //在全局命名空间中的全局变量
namespace Ns {
int j; //在Ns命名空间中的全局变量
}
int main()
{
i = 5; //为全局变量i赋值
Ns::j = 6;//为全局变量j赋值
{ //子块1
using namespace Ns; //使得在当前块中可以直接引用Ns命名空间的标识符
int i; //局部变量,局部作用域
i = 7;
cout << "i=" << i << endl; //输出7
cout << "j=" << j << endl; //输出6
}
cout << "i=" << i << endl; //输出5
return 0;
}
运行结果为:
i=7
j=6
i=5
注意:具有命名空间作用域的变量也称为全局变量。mian函数结束才销毁。
2>.可见性:
作用域可见性的一般规则如下:
(1) 声明在前,引用在后;
(2) 在同一作用域中,不能声明同名的标识符;
(3) 在没有互相包含关系的不同的作用域中声明的同名标识符,互不影响;
(4)若有两个或多个具有包含关系的作用域声明了同名标识符,则外层标识符在内层不可见;
注意:作用域和可见性的原则不只使用于变量名,也适用于其他各种标识符,包括常量名、用户定义的类型名、函数名、枚举类型的取值等。
二、对象的生存期:
1>静态生存期:
对象的生存期与程序的运行期相同,则它具有静态生存期。
如果要在函数的局部作用域中声明具有静态生存期的对象,则要使用关键字static。
Static int i;
局部作用域中静态变量特点:它不会随着函数调用而产生一个副本,也不会随着函数返回而失效。
注意:定义时未指定初值的基本类型静态变生存期量,会被赋予0值初始化;
2> 动态生存期:
局部生存期对象诞生于声明点,结束于声明所在的块执行完毕之时.
三、类的静态成员:
模块间对内存中数据的共享是通过函数与函数之间的数据共享来实现的,其中包括两个途径:参数传递,全局变量。
静态成员是解决同一个类的不同对象之间数据与函数共享问题的。
1>静态数据成员:
一个类的所有对象具有相同的属性:指属性的个数,名称,数据类型相同,各个对象的属性值则可以各不相同。
类属性:描述类的所有对象共同特征的一个数据项,对于任何对象实例,它的属性值是相同的。
静态数据成员具有静态生存期。由于静态数据成员不属于任何一个对象,因此可以通过类名对它进行访问:类名::标识符。
注意:
之所以类的静态数据成员需要在类定义之外再加以定义,是因为需要以这样的方式专门为他们分配空间;非静态数据成员无须以此方式定义,因为他们的空间是与他们所属对象的空间同时分配的。
例:具有静态数据成员的point 类。
#include<iostream>
using namespace std;
class Point //Point类定义
{
public: //外部接口
Point (int x = 0, int y = 0) :x(x), y(y) //构造函数
{
count++; //在构造函数中对count累加,所有对象共同维护同一个count
}
Point (Point &p) //复制构造函数
{
x = p.x;
y = p.y;
count++;
}
~Point() { count--; }
int getX() { return x; }
int getY() { return y; }
void showCount() //输出静态数据成员
{
cout << "Object count=" << count << endl;
}
private: //私有数据成员
int x, y;
static int count; //静态数据成员声明,用于记录点的个数
};
int Point::count = 0; //静态数据成员定义和初始化,使用类名限定
int main()
{
Point a(4, 5); //定义对象a,其构造函数会使count增1
cout << "Point A:" << a.getX() << "," << a.getY();
a.showCount(); //输出对象个数
Point b(a); //定义对象b,其构造函数会使count增1
cout << "Point B:" << b.getX() << "," << b.getY();
b.showCount(); //输出对象个数
return 0;
}
运行结果为:
Point A:4,5Object count=1
Point B:4,5Object count=2
2>静态函数成员:
1、静态成员函数解决的问题:
(1)不依赖对象就可以访问静态成员变量;
(2)必须保证静态成员变量的安全性;
(3)方便快捷得获取静态成员变量的值
静态成员函数的定义:接通过static关键字修饰成员函数即可。
为了便于理解,我们先上一段代码来理解一下静态成员函数的性质:
#include <stdio.h>
class Demo
{
private:
int i;
public:
int getI();
static void StaticFunc(const char* s);
static void StaticSetI(Demo& d, int v);
};
int Demo::getI()
{
return i;
}
void Demo::StaticFunc(const char* s)
{
printf("StaticFunc: %s\n", s);
}
void Demo::StaticSetI(Demo& d, int v)
{
d.i = v;
}
int main()
{
Demo::StaticFunc("main Begin...");
Demo d;
d.StaticSetI(d, 20);
printf("d.i = %d\n", d.getI());
Demo::StaticSetI(d, 10);
printf("d.i = %d\n", d.getI());
Demo::StaticFunc("main End...");
return 0;
}
以上代码运行的结果为:
StaticFunc: main Begin...
d.i = 20
d.i = 10
StaticFunc: main End...
两个静态成员函数:
static void StaticFunc(const char* s);
static void StaticSetI(Demo& d, int v);
可以看出静态成员函数的性质大体如下:
(1)静态成员函数是类中特殊的成员函数
(2)静态成员函数属于整个类所有
(3)可以通过类名(作用域访问)直接访问公有静态成员函数
(4)可以通过对象名访问公有静态成员函数
注意:
(1)静态成员函数不能访问普通成员变量(函数),需通过对象间接访问成员变量(函数);
(2)静态成员函数是类中的特殊的成员函数
(3)静态成员函数没有隐藏的this指针
(4)静态成员函数可以通过类名直接访问
(5)静态成员函数可以通过对象访问
(6)静态成员函数只能直接访问静态成员变量(函数),而不能直接访问普通成员变量(函数)