static 修饰类
C++扩展了 static 在类中的语意,用于实现在同一个类,多个对象间数据共享,协调行为的目的。
静态变量有全局变量的优势,又不会像全变量一样被滥用。
而这一类变量,即可以通过类来管理,也可以通过类的静态函数来管理。
类的静态成员,属于类,也属于对象,但终归属于类。
static 修饰数据成员
语法规则
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
_m = 100;
_n = 200;
}
~MyClass()
{}
int _m;
int _n;
static int _share = 100;
};
int main()
{
MyClass a;
cout << a._share << endl;
return 0;
}
上面代码在编译的时候会报错:
所以:static修饰数据成员需要初始化,不可以类内初始化。
在类外初始化,并且需要类名空间,且不需要static
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
_m = 100;
_n = 200;
}
~MyClass()
{}
int _m;
int _n;
static int _share;
};
int MyClass::_share = 100;
int main()
{
MyClass a;
cout << a._share << endl;
return 0;
}
运行结果为:
类的声明与实现分开的时候如果把初始化放在了class.h里面之后就会出现class.h即include在了class.cpp又include 在了main.cpp 就会出现重复声明,出现错误。所以static修饰变量初始化在class.cpp文件里面。并且我们把声明放在.h文件里面,把定义放在.cpp文件里面。
B.h
#pragma once
class B
{
public:
B();
static int _m; //声明
};
B.cpp
#include "B.h"
int B::_m = 200; //定义
B::B()
{
}
main.c
#include "B.h"
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
_m = 100;
_n = 200;
}
~MyClass()
{}
int _m;
int _n;
static int _share;
};
int MyClass::_share = 100;
int main()
{
MyClass a;
cout << a._share << endl;
return 0;
}
Static声明的数据成员不占用类对象的大小,存储在data段的rw段
在同一个类中,定义的类内成员m和n存储在内存中的栈区,
两个分区的变量通过MyClass类产生关系来维系其为整体。
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
_m = 100;
_n = 200;
}
~MyClass()
{}
int _m;
int _n;
static int _share;
};
int MyClass::_share = 100;
int main()
{
MyClass a;
cout << a._share << endl;
cout << sizeof(MyClass) << endl;
cout << sizeof(a) << endl;
return 0;
}
运行结果为:
大小都是8,占用的是两个类内私有数据成员int类型的大小。
访问
类的静态成员,属于类,也属于对象,但终归属于类。
既可以通过对象访问,也可以不通过对象,直接通过类名访问。
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
_m = 100;
_n = 200;
}
~MyClass()
{}
int _m;
int _n;
static int _share;
};
int MyClass::_share = 100;
int main()
{
MyClass a;
cout << a._share << endl;
cout<<MyClass::_share << endl;
return 0;
}
m和n的存在依赖于对象的生成,static修饰的数据成员在对象还没有生成的时候就已经存在了。并且属于命名空间MyClass,所以就有了上面的第二种访问方式。即使没有对象生成也可以进行访问,前提是不受private的限制。如果有private的限制也不可以进行访问。
static 修饰数据成员小结
static 修饰成员函数
为了管理静态成员,C++提供了静态函数,以对外提供接口。并且静态函数只能访问静态成员。
我们前面说过,如果static修饰的类内数据成员被private限制之后就不能直接使用命名空间进行访问。而需要使用函数,但是static修饰的类内数据成员是在类对象生成之前就已经存在的,所以不能使用类内私有成员函数对于static修饰的数据成员进行操作。所以我们需要在没有对象的时候也可以管理static修饰的数据成员,那么我们就需要使用static修饰函数,目的就是为了管理静态变量。
统计函数的执行次数:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
_m = 100;
_n = 200;
}
~MyClass()
{}
void foo()
{
cout << "void foo()" << endl;
fooCount++;
}
static int invokefoofCount()
{
return fooCount;
}
private:
int _m;
int _n;
static int fooCount;
};
int MyClass::fooCount = 0;
int main()
{
{
MyClass a, b, c;
a.foo();
b.foo();
c.foo();
cout << a.invokefoofCount() << endl;
}
cout << MyClass::invokefoofCount() << endl;
return 0;
}
运行结果为:
一塔湖图
实现多个学校各自有一塔,一湖,但是共用一个图书馆
#include <iostream>
using namespace std;
class Univesity
{
public:
Univesity(string t, string l)
{
_tower = t;
_lake = l;
}
static string & getLib()
{
return _lib;
}
void dis()
{
cout << "塔:" << _tower << "湖:" << _lake << "图:" << _lib << endl;
}
private:
string _tower;
string _lake;
static string _lib;
};
string Univesity::_lib = " ";
int main()
{
Univesity pk("博雅塔","未名湖");
Univesity bs("电视台","大明湖");
Univesity xdf("雷峰台", "东方湖");
Univesity::getLib() += "计算机基础 ";
pk.dis();
Univesity::getLib() += "数据结构 ";
bs.dis();
Univesity::getLib() += "计算机网络 ";
xdf.dis();
return 0;
}
运行结果为:
私有成员可以通过返回引用的方式修改数据。
体现出来图书馆共享
语法规则
static修饰成员函数的作用主要用来管理静态变量
类内声明,类外定义方式:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{}
~MyClass()
{}
static void manageA();
private:
static int a;
};
int MyClass::a = 100;
void MyClass:: manageA()
{
}
int main()
{
return 0;
}
静态成员函数只能访问静态成员变量和静态成员函数,不能访问非静态的成员变量和成员函数。
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{}
~MyClass()
{}
static void manageA();
static void manageB()
{}
void foo()
{
}
private:
static int a;
int x;
};
int MyClass::a = 100;
void MyClass:: manageA()
{
cout << a <<endl;
manageB(); //编译通过
cout << x <<endl; //编译器报错:非静态成员必须与特定对象相对
foo(); //编译器报错:非静态成员必须与特定对象相对
}
int main()
{
return 0;
}
对于上面MyClass类:
int main()
{
MyClass a;
a.manageA();
a.manageB();
MyClass::manageA();
MyClass::manageA();
return 0;
}
a.manageA();
a.manageB();
里面会有默认的参数this指针,所以可以访问到类内的所有成员变量和成员函数。
但是:
MyClass::manageA();
MyClass::manageA();
上面这种情况没有对象,那么就没有this指针,所以只能访问static 修饰的类内数据成员和类内函数。
静态成员函数中没有this指针。
非静态函数访问静态的成员:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{}
~MyClass()
{}
static void manageA();
static void manageB()
{}
void foo()
{
cout << a << endl;
manageA();
}
private:
static int a;
int x;
};
int MyClass::a = 100;
void MyClass:: manageA()
{
cout << a <<endl;
}
int main()
{
MyClass a;
return 0;
}
非静态成员可以访问static修饰的变量和成员。
应用:协调:取号服务
#include <iostream>
using namespace std;
class Server
{
public:
Server(char name)
:_name(name) {}
void serverOne()
{
if (_openFlag && _lastServedIdx < _turnCount)
{
_lastServedIdx++;
cout << "Server: " << _name << " is serving " << _lastServedIdx << endl;
}
if (_lastServedIdx >= _turnCount)
_openFlag = false;
}
static int getTurn()
{
++_turnCount;
return _turnCount;
}
static bool stillOpen()
{
return _openFlag;
}
private:
char _name;
static int _turnCount;
static int _lastServedIdx;
static bool _openFlag;
};
int Server::_turnCount = 0;
int Server::_lastServedIdx = 0;
bool Server::_openFlag = true;
int main()
{
Server s1('A'), s2('B');
int num;
cout << "How many in your groups" << endl;
cin >> num;
cout << "your turns are" << endl;
for (int i = 0; i < num; i++)
{
cout << Server::getTurn() << endl;
}
do
{
s1.serverOne();
s2.serverOne();
} while (Server::stillOpen());
cout << "now closing server" << endl;
return 0;
}
运行结果为: