凡事就怕反向flag
(也许是我的文章名称起得太钓鱼执法了?那篇日常的浏览量噌噌得涨哎。。。)
下面我们介绍这章节的最后一部分内容:
静态数据成员和成员函数
静态数据成员
- 至多初始化一次
- 若没有显式初始化
- 静态整型的数据成员缺省初始化为0
- 静态抽象数据类型(类对象)的数据成员默认调用其缺省构造函数
- 显式初始化
- 静态常量整数成员可以在类定义中初始化(const static integral)
- 其他情况必须在类外部定义和初始化
- static类型变量不能用构造函数初始化列表进行初始化
#include<iostream>
using namespace std;
class Data{
public:
Data(int x=1) {cout<<"num1="<<(num1=x)<<endl;}
//static类型是不能用构造函数初始化列表进行初始化的
void print() const{cout<<"num2="<<num2<<endl;}
private:
static int num1;
const static int num2=10;
//const static int类型可以直接在定义的时候进行初始化
};
int Data::num1;
class Test{
public:
Test(){};
static Data member;
};
Data Test::member(3);
//Data Test::member=Data(3,4);
静态成员函数
- 没有this指针
- 不能添加const关键字
- 不能访问非静态数据成员,不能调用非静态成员函数,只能调用静态的数据成员和成员函数
- 调用静态成员函数:
- public static member
① 通过对象直接访问
② 通过类名::
访问 - private static member
① 通过对象调用其他(public)成员函数访问
- public static member
可以看看下面的栗子:
起手,在外部通过 类名::
直接调用 member.print()
因为member是static类型的成员对象,并且有特意定义的构造函数,所以会立刻进行初始化,输出num1=3
申请obj对象,开辟obj的Data类成员member所需要的空间
因为member是static类型的成员对象,至多初始化一次
所以不会出现num1=3的输出
#include<iostream>
using namespace std;
class Data{
public:
Data(int x=1) {cout<<"num1="<<(num1=x)<<endl;}
//static类型是不能用构造函数初始化列表进行初始化的
void print() const{cout<<"num2="<<num2<<endl;}
private:
static int num1;
const static int num2=10;
//const static int类型可以直接在定义的时候进行初始化
};
int Data::num1;
class Test{
public:
Test(){};
static Data member;
};
Data Test::member(3);
//Data Test::member=Data(3,4);
int main()
{
Test::member.print();
Test obj;
obj.member.print();
system("pause");
return 0;
}
// Output
num1=3
num2=10
num2=10
最后来看看这两道题
T1
#include <iostream>
using namespace std;
class Student
{
public:
Student(){++count;};
~Student(){--count;};
static int count;
};
int Student::count=0;
Student s;
int main()
{
Student a;
cout<<a.count<<" students"<<endl;
Student * b=new Student();
cout<<b->count<<" students"<<endl;
{
Student a;
cout<<a.count<<" students"<<endl;
}
cout<<Student::count<<" students"<<endl;
delete b;
cout<<Student::count<<" students"<<endl;
system("pause");
return 0;
}
输出:
2 students
3 students
4 students
3 students
2 students
这是怎么回事呢?
首先我们锁定所有产生输出的地方:5处
First.
cout<<a.count<<" students"<<endl;
我们关心count的值
const是static类型,有静态全局性
count的改变出现在构造函数和析构函数中
在第一次输出之前,一共申请了两次对象:
Student s; //全局对象 count=1
Student a; //mian函数中的对象 count=2
所以输出:
2 students
Second.
Student * b=new Student();
cout<<b->count<<" students"<<endl;
在第二次输出之前,又申请了一个对象b(main函数作用域)count=3
Third. && Fourth.
{
Student a;
cout<<a.count<<" students"<<endl;
}
cout<<Student::count<<" students"<<endl;
在局部作用域中又申请了一个对象:a,count=4
完成第三次输出后,局部作用域结束,调用析构函数解构局部对象a,count=3
Fifth.
delete b;
cout<<Student::count<<" students"<<endl;
删除对象b,count=2,完成第五次输出
T2
#include <iostream>
using namespace std;
class X
{
int num;
public:
X(int i) {num=i;}
X() {};
X(X &a) {num=a.num+1;}
void print(){cout<<num<<endl;}
X &pro() {return *this;}
X clone() {return *this;}
};
int main()
{
X a(0),b(a),c(0),d;
d=a;
d.print();
b.print();
X y=b;
y.print();
y.pro().print();
y.clone().print();
system("pause");
return 0;
}
输出:
0
1
2
2
3
来解释一下
X a(0),b(a),c(0),d;
d=a;
对象申请上就有大学问:
a.num=0,c.num=0
b的申请调用了拷贝构造函数(用对象初始化对象),b.num=1
然而,d的申请是普通的赋值,d.num=0
X y=b;
y的申请调用了拷贝构造函数(用对象初始化对象),y.num=2
X &pro() {return *this;}
y.pro().print();
pro函数返回引用,考察this指针实现级联函数调用
引用是原对象的影之分身,两者共享内存,所以之后的print输出的是y.num
X clone() {return *this;}
y.clone().print();
clone函数在返回时,调用了拷贝构造函数创建了一个新对象,num=3
Time tmp=y.clone();
//tmp是用对象初始化的,所以调用的拷贝构造函数,num=3
tmp.print();