不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。
目录
6.3 this指针的本质和常函数(const修饰成员函数)
一、静态成员变量
在一个类中,若将一个成员变量声明为static,这种成员称为静态成员变量。与一般的数据成员不同,无论建立了多少个对象,都只有一个静态数据的拷贝。静态成员变量,属于某个类,所有对象共享。
静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配空间。
|
class Person{
public:
//类的静态成员属性
static int sNum;
private:
static int sOther;
};
//类外初始化,初始化时不加static
int Person::sNum = 0;
int Person::sOther = 0;
int main()
{
//1. 通过类名直接访问
Person::sNum = 100;
cout << "Person::sNum:" << Person::sNum << endl;
//2. 通过对象访问
Person p1, p2;
p1.sNum = 200;
cout << "p1.sNum:" << p1.sNum << endl;
cout << "p2.sNum:" << p2.sNum << endl;
//3. 静态成员也有访问权限,类外不能访问私有成员
//cout << "Person::sOther:" << Person::sOther << endl;
Person p3;
//cout << "p3.sOther:" << p3.sOther << endl;
system("pause");
return EXIT_SUCCESS;
}
二、 静态成员函数
在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数使用方式和静态变量一样,同样在对象没有创建前,即可通过类名调用。静态成员函数主要为了访问静态变量,但是,不能访问普通成员变量。
静态成员函数的意义:不在于信息共享和数据沟通,而在于管理静态数据成员,完成对静态数据成员的封装。
普通成员函数可访问静态成员变量、可以访问非静态成员变量
静态成员函数可访问静态成员变量,不可以访问非静态成员变量
class Person{
public:
//普通成员函数可以访问static和non-static成员属性
void changeParam1(int param){
mParam = param;
sNum = param;
}
//静态成员函数只能访问static成员属性
static void changeParam2(int param){
//mParam = param; //无法访问
sNum = param;
}
private:
static void changeParam3(int param){
//mParam = param; //无法访问
sNum = param;
}
public:
int mParam;
static int sNum;
};
//静态成员属性类外初始化
int Person::sNum = 0;
int main(){
//1. 类名直接调用
Person::changeParam2(100);
//2. 通过对象调用
Person p;
p.changeParam2(200);
//3. 静态成员函数也有访问权限
//Person::changeParam3(100); //类外无法访问私有静态成员函数
//Person p1;
//p1.changeParam3(200);
return EXIT_SUCCESS;
}
三、const静态成员属性
如果一个类的成员,既要实现共享,又要实现不可改变,那就用 static const 修饰。
定义静态const数据成员时,最好在类内部初始化。
class Person{
public:
//static const int mShare = 10;
const static int mShare = 10; //只读区,不可修改
};
int main(){
cout << Person::mShare << endl;
//Person::mShare = 20;
return EXIT_SUCCESS;
}
四、单例模式
Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其默认构造函数和拷贝构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
单利固定格式:
class Printer
{
private:
Printer() {}; // 1、构造函数私有化
Printer(const Printer &) {}; // 2、拷贝函数私有化
static Printer* singlePrinter; // 3、指针私有化
public:
static Printer* getInstance() // 5、对外提供getInstance
{
return singlePrinter;
}
};
Printer * Printer::singlePrinter = new Printer; //4、初始化指针
void test()
{
Printer* p1 = Printer::getInstance(); //单例实例化
}
五、成员变量和函数的存储
空类占用的内存空间:1字节
1、非静态成员变量 属于类的对象上
2、静态成员变量 不属于类对象上
3、非静态成员函数 不属于类对象上 只有一份实例
4、静态成员函数 不属于类对象上 只有一份实例
六、this指针
6.1 this指针工作原理
c++的数据和操作也是分开存储,并且每一个非内联成员函数(non-inline member function)只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这一块代码是如何区分那个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象。
c++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,也就是说虽然我们没有写上this指针,编译器在编译的时候也是会加上的。因此this也称为“指向本对象的指针”,this指针并不是对象的一部分,不会影响sizeof(对象)的结果。
this指针是C++实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。一般情况下,并不写this,而是让系统进行默认设置。
成员函数通过this指针即可知道操作的是那个对象的数据。This指针是一种隐含指针,它隐含于每个类的非静态成员函数中。This指针无需定义,直接使用即可。
注意:静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量。 |
下图是 c++编译器对普通成员函数的内部处理
6.2 this指针使用
使用场景:
- 当形参和成员变量同名时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身,可使用return *this.
class Person
{
public:
Person(int age) //每一个非静态成员函数内部都隐藏加了一个this指针
{
//1、this可以解决名称冲突
this->age = age;
}
//2、在类的非静态成员函数中返回对象本身
Person& personAddAge(Person & p)
{
this->age += p.age;
return *this; // *this指向p2的本体 this指向p2的指针
}
int age;
};
void test01()
{
Person p1(10);
cout << "p1的年龄为: " << p1.age << endl;
Person p2(10);
p2.personAddAge(p1).personAddAge(p1).personAddAge(p1); //链式编程思想
cout << "p2的年龄为: " << p2.age << endl;
}
6.3 this指针的本质和常函数(const修饰成员函数)
|
常函数的格式:
返回值类型 函数名() const
例子:void showAge() const
- 用const修饰的成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中普通成员变量。
- 当成员变量类型符前用mutable修饰时例外。
class Person{
public:
Person(){
this->mAge = 0;
this->mID = 0;
}
//在函数括号后面加上const,修饰成员变量不可修改,除了mutable变量
void sonmeOperate() const{
//this->mAge = 200; //mAge不可修改
this->mID = 10;
}
void ShowPerson(){
cout << "ID:" << mID << " mAge:" << mAge << endl;
}
private:
int mAge;
mutable int mID;
};
int main(){
Person person;
person.sonmeOperate();
person.ShowPerson();
system("pause");
return EXIT_SUCCESS;
}
6.4 常对象(const修饰对象)
|
class Person{
public:
Person(){
this->mAge = 0;
this->mID = 0;
}
void ChangePerson() const{
mAge = 100;
mID = 100;
}
void ShowPerson(){
this->mAge = 1000;
cout << "ID:" << this->mID << " Age:" << this->mAge << endl;
}
public:
int mAge;
mutable int mID;
};
void test(){
const Person person;
//1. 可访问数据成员
cout << "Age:" << person.mAge << endl;
//person.mAge = 300; //不可修改
person.mID = 1001; //但是可以修改mutable修饰的成员变量
//2. 只能访问const修饰的函数
//person.ShowPerson();
person.ChangePerson();
}