static在C语言中用法:
1)全局量被静态关键字修饰只在本文件中有效,仍存储在静态区,生命周期没变。
2)函数被静态关键字修饰只在本文件中有效
3)在函数中局部变量用静态关键字定义,生命周期存在于整个程序中,但变量只能在函数中访问,且此只能创建初始化一份
4)static 修饰变量还有一特点,当变量未初始化时,默认初始化为 0。这是因为在静态存储区,所有内存都被默认置为 0,有时这一特点可减少工作量。
static在C++中用法:
1)类的静态成员变量
被static修饰的成员变量和成员方法独立于该类的任何对象。 也就是说,它不依赖类特定的实例,被类的所有实例共享。 只要这个类被加载,编译器就能根据类名在运行时数据区内找到他们。 按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。
对象的内存中包含了成员变量,不同的对象占用不同的内存,有不同的成员数据并共用成员函数方法,这使得不同对象的成员变量相互独立,它们的值不受其他对象的影响。例如有两个相同类型的对象 a、b,它们都有一个成员变量 m_name,那么修改 a.m_name 的值不会影响 b.m_name 的值。
可是有时候我们希望在多个对象之间共享数据,对象 a 改变了某份数据后对象 b 可以检测到。共享数据的典型使用场景是计数,以前面的 Student 类为例,如果我们想知道班级中共有多少名学生,就可以设置一份共享的变量,每次创建对象时让该变量加 1。
在C++中,我们可以使用静态成员变量来实现多个对象共享数据的目标。
静态成员变量是一种特殊的成员变量,它被关键字static修饰,例如:
class Student{
public:
Student(char *name, int age, float score);
void show();
public:
static int m_total; //静态成员变量 m_total,用来统计学生的人数
private:
char *m_name;
int m_age;
float m_score;
};
static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,
也只为 m_total 分配一份内存,所有对象使用的都是这份内存中的数据。
当某个对象修改了 m_total,也会影响到其他对象。
static 成员变量必须在类声明的外部初始化,具体形式为:
type class::name = value;
type 是变量的类型,class 是类名,name 是变量名,value 是初始值。将上面的 m_total 初始化:
int Student::m_total = 0;
静态成员变量在初始化时不能再加 static,但必须要有数据类型。
被 private、protected、public 修饰的静态成员变量都可以用这种方式初始化。
注意:static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。反过来说,没有在类外初始化的 static 成员变量不能使用。
成员变量既可以通过对象来访问,也可以通过类来访问。请看下面的例子:
//通过类访问 static 成员变量
Student::m_total = 10;
//通过对象访问 static 成员变量
Student stu("小明", 15, 92.5f);
stu.m_total = 20;
//通过对象指针访问 static 成员变量
Student *pstu = new Student("李华", 16, 96);
pstu -> m_total = 20;
2)类的静态成员函数
在类中,static 除了可以声明静态成员变量,还可以声明静态成员函数。
普通成员函数可以访问所有成员(包括成员变量和成员函数),静态成员函数只能访问静态成员(包括静态成员变量和静态成员函数)。
编译器在编译一个普通成员函数时,会隐式地增加一个形参 this指针,并把当前对象的地址赋值给 this,所以普通成员函数只能在创建对象后通过对象来调用,因为它需要当前对象的地址。而静态成员函数可以通过类来直接调用,编译器不会为它增加形参 this,它不需要当前对象的地址,所以不管有没有创建对象,都可以调用静态成员函数。
class Object
{
private:
int value;
static Object objx;
public:
Object(int x = 0) :value(x) { cout << "create object" << endl; }
~Object() { cout << "destroy object" << endl; }
//void SetValue(Object* const this,int x=0)
void SetValue(int x = 0) { value = x; }//隐式添加this
//int GetValue(const Object* const this)
int GetValue() const { return value; }//隐式添加this
static Object& GetObject();//static修饰则函数没有this指针
};
静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
解释:普通成员变量占用对象的内存,静态成员函数没有 this 指针,不知道指向哪个对象,无法访问对象的成员变量,也就是说静态成员函数不能访问普通成员变量,只能访问静态成员变量。 普通成员函数必须通过对象才能调用,而静态成员函数没有 this 指针,无法在函数体内部访问某个对象,所以不能调用普通成员函数,只能调用静态成员函数。
为什么要有this指针?
1.节省空间
2.所有类对象公用成员函数方法,数据都是私有的,用this指针区分不同对象调用成员函数。
#include <iostream>
using namespace std;
class Student {
public:
Student(const char *name, int age, float score);
void show();
public: //声明静态成员函数
static int getTotal();
static float getPoints();
private:
static int m_total; //总人数
static float m_points; //总成绩
private:
const char *m_name;
int m_age;
float m_score;
};
int Student::m_total = 0;//静态成员必须在类外初始化
float Student::m_points = 0.0;//静态成员必须在类外初始化
Student::Student(const char *name, int age, float score) : m_name(name), m_age(age), m_score(score) {
m_total++;
m_points += score;
}
void Student::show() {
cout << m_name << "的年龄是" << m_age << ",成绩是" << m_score << endl;
}
//定义静态成员函数
int Student::getTotal() {
return m_total;
}
float Student::getPoints() {
return m_points;
}
int main() {
(new Student("小明", 15, 90.6))->show();
(new Student("李磊", 16, 80.5))->show();
(new Student("张华", 16, 99.0))->show();
(new Student("王康", 14, 60.8))->show();
int total = Student::getTotal();
float points = Student::getPoints();
cout << "当前共有" << total << "名学生,总成绩是" << points << ",平均分是" << points / total << endl;
return 0;
}
总人数 m_total 和总成绩 m_points 由各个对象累加得到,必须声明为 static 才能共享;getTotal()、getPoints() 分别用来获取总人数和总成绩,为了访问 static 成员变量,我们将这两个函数也声明为 static。
在C++中,静态成员函数的主要目的是访问静态成员。getTotal()、getPoints() 当然也可以声明为普通成员函数,但是它们都只对静态成员进行操作,加上 static 语义更加明确。
和静态成员变量类似,静态成员函数在声明时要加 static,在定义时不能加 static。