文章目录
4.0概要
学习目的:
- 掌握类中的特殊成员
- 掌握友元模式
- 掌握单例模式
课程内容:
- this指针
- static成员
- const成员
- friend
重点难点:
- 静态成员
- 友元关系
4.1 this指针
- this指针是系统自动生成的,且隐藏的。
- this指针不是对象的一部分,作用域在类内部。
- 类的普通函数访问类的普通成员时,this指针总是指向调用者对象。
- 也就是说this指针会藏在所有的普通成员函数里面,谁调用当前这个函数,this指针就会指向谁。
数据成员是每个对象都有单独的一份。
而成员函数整个类只有一份,用的时候哪个对象需要去调用这个成员函数,那他就归哪个成员函数调用。
如果一个类里面有个成员叫张三,在一个函数里面也传了一个相同名字的参数,那么如何去区别这两个张三呢?
正常:
class MyClass {
public:
int num;
void setNum(int n) {
num = n;
}
int getNum() {
return num;
}
};
int main() {
MyClass obj_1;
obj_1.setNum(10);
cout << "num = " << obj_1.getNum() << endl;
return 0;
}
不正常:
class MyClass {
public:
int num;
void setNum(int num) { //区分不了num了
num = num;
}
int getNum() {
return num;
}
};
int main() {
MyClass obj_1;
obj_1.setNum(10);
cout << "num = " << obj_1.getNum() << endl;
return 0;
}
this指针:
class MyClass {
public:
int num;
void setNum(int num) {
//num = num;
this->num = num;//名字相同用this指针来进行区分
}//this指针不能改指向
int getNum() {
return num;//return this->num;//此处this省略了
}
MyClass getThis1() {//返回这个函数自己
return *this;//返回一个对象的值
}
MyClass* getThis2() {//这个也可以
return this;//返回一个指向对象的指针
}
};
int main() {
MyClass obj_1;
obj_1.setNum(10);
cout << "num = " << obj_1.getNum() << endl;
return 0;
}
就像这个int getNum();
表面上是返回return num;
,实际上是返回return this->num;
。
4.2 static成员
- 在C++类中声明成员时,加上static关键字就是static成员了。
- 静态成员分为静态数据成员和静态函数成员
静态数据成员
class ClassName {
public:
ClassName();
~ClassName();
static int num; //静态数据成员
};
ClassName::ClassName() {
num = 0; //这里直接给num=0会报错
}
ClassName::~ClassName() {}
int main() {
ClassName obj_1;
cout << "num = " << obj_1.num << endl;
return 0;
}
上面会错,为什么呢?
因为static int num;
怎么解决?
class ClassName {
public:
ClassName();
~ClassName();
static int num;
};
int ClassName::num = 0; //多了这行
ClassName::ClassName() {} //去掉了原来的num=0
ClassName::~ClassName() {}
int main() {
ClassName obj_1;
cout << "num = " << obj_1.num << endl;
return 0;
}
在类的外面给上一个int ClassName::num = 0;
就可以了。
一个类不管有多少个对象。所有的对象都全部共享着同一段静态数据成员的内存。
class ClassName {
public:
ClassName();
~ClassName();
static int num;
};
int ClassName::num = 0;
ClassName::ClassName() {}
ClassName::~ClassName() {}
int main() {
ClassName obj_1;
cout << "obj_1.num = " << obj_1.num << endl;
obj_1.num = 10;
ClassName obj_2;
cout << "obj_2.num = " << obj_2.num << endl;
return 0;
}
![]() | ![]() |
---|
这里面,通过添加一行obj_1.num = 10;
就让obj_2.num
的值改变了。说明用的是同一个内存。
sizeof(obj_1)=1;
说明obj_1占用1个字节。
而上面的static int num;
是占用4个字节的。
这说明num
不在obj_1
里面。它存在这个类里面。
上面说num
存在类里面,那么为什么sizeof(ClassName) = 1;
呢?
那是因为类型是求不了字节数的,所以 他给你创建了一个对象,既然是对象,那就是一个字节。
int main() {
ClassName obj_1;
cout << "obj_1.num = " << obj_1.num << endl;
obj_1.num = 10;
ClassName obj_2;
cout << "obj_2.num = " << obj_2.num << endl;
cout << "sizeof(obj_1) = " << sizeof(obj_1) << endl;
cout << "sizeof(ClassName) = " << sizeof(ClassName) << endl;
return 0;
}
静态成员函数
class ClassName {
public:
static int num;
static void testFunc_1();
static void testFunc_2(){
cout << "ClassName::testFunc_2()" << endl;
}
};
int ClassName::num = 0;
void ClassName::testFunc_1() { //说的是这个函数
cout << "ClassName::testFunc_1()" << endl;
}
这个静态成员函数只在类的里面有static,类的外面不要写static。
class ClassName {
public:
ClassName();
~ClassName();
int val;
static int num;
static void testFunc_1();
static void testFunc_2() {
cout << "ClassName::testFunc_2()" << endl;
}
};
int ClassName::num = 0;
void ClassName::testFunc_1() {
cout << "ClassName::testFunc_1()" << endl;
}
ClassName::ClassName() { //构造函数的计数功能实现
num++;//计数
}
ClassName::~ClassName() {}
int main() {
ClassName obj_1;
cout << "obj_1.num = " << obj_1.num << endl;
ClassName obj_2;
cout << "obj_2.num = " << obj_2.num << endl;
obj_2.testFunc_1();
(&obj_1)->testFunc_2();//下面2行和这行一个作用。
//ClassName* p = &obj_1;
//p->testFunc_2();
ClassName::num;
ClassName::testFunc_1();
ClassName::testFunc_2();
return 0;
}
静态成员不能用类里面的普通的数据成员和普通的成员函数,甚至连this指针都没有。因为静态成员的生命周期长。
static int num;
static void testFunc_1();
static void testFunc_2() {
cout << "ClassName::testFunc_2()" << endl;
}
单例模式
单例模式:一种设计模式,要求创建一个只能实例化一个对象的类。
class SingleInstance {
public:
~SingleInstance();
static SingleInstance* getInstance();
private:
SingleInstance();//防止类在外面创建对象
SingleInstance(const SingleInstance& obj);//防止拷贝构造
static SingleInstance* pInstance;//创建一个静态指针。这个静态指针也是一个静态的数据成员
};
SingleInstance* SingleInstance::getInstance() {
if (pInstance==NULL) {
pInstance = new SingleInstance;
}
return pInstance;
}
SingleInstance* SingleInstance::pInstance = NULL;
SingleInstance::SingleInstance() {
}
SingleInstance::SingleInstance(const SingleInstance& obj) {
}
SingleInstance::~SingleInstance() {
}
int main() {
SingleInstance* p1 = SingleInstance::getInstance();
SingleInstance* p2 = SingleInstance::getInstance();
SingleInstance* p3 = SingleInstance::getInstance();
cout << hex << p1 << endl;
cout << hex << p2 << endl;
cout << hex << p3 << endl;
return 0;
}
为什么这3个指针一样呢?
因为pInstance
这个对象虽然初始化的时候是为空的,但是在if (pInstance==NULL)
创建成功了就不为空了,不为空就直接return ipInstance;
了。
单例模式代码讲解
class SingleInstance {
public:
~SingleInstance();
static SingleInstance* getInstance();
private:
SingleInstance();//防止类在外面创建对象
SingleInstance(const SingleInstance& obj);//防止拷贝构造
static SingleInstance* pInstance;//创建一个静态指针。这个静态指针也是一个静态的数据成员
};
SingleInstance* SingleInstance::pInstance = NULL;
SingleInstance* SingleInstance::getInstance() {
if (pInstance==NULL) {
pInstance = new SingleInstance;
}
return pInstance;
}
SingleInstance::SingleInstance() {}
SingleInstance::SingleInstance(const SingleInstance& obj) {}
SingleInstance::~SingleInstance() {}
int main() {
SingleInstance* p1 = SingleInstance::getInstance();
SingleInstance* p2 = SingleInstance::getInstance();
SingleInstance* p3 = SingleInstance::getInstance();
cout << hex << p1 << endl;
cout << hex << p2 << endl;
cout << hex << p3 << endl;
return 0;
}
SingleInstance
类定义:~SingleInstance();
:这是一个析构函数的声明,它将在对象生命周期结束时被调用以释放资源。static SingleInstance* getInstance();
:这是一个静态成员函数,用于获取类的唯一实例。SingleInstance();
:这是一个私有构造函数的声明,它防止了类的外部实例化。SingleInstance(const SingleInstance& obj);
:这是一个私有拷贝构造函数的声明,它防止了类的拷贝。static SingleInstance* pInstance;
:这是一个静态指针成员,用于存储类的唯一实例。
- 静态成员初始化:
SingleInstance* SingleInstance::pInstance = NULL;
:在类外部初始化静态成员pInstance
为NULL
。
getInstance
函数实现:- 这个函数检查静态指针
pInstance
是否为NULL
。如果是,它将创建一个新的SingleInstance
对象并将其地址赋给pInstance
。如果不是,它将直接返回pInstance
,即已经存在的唯一实例。
- 这个函数检查静态指针
main
函数:- 在
main
函数中,通过调用SingleInstance::getInstance()
三次来获取类的唯一实例的三个不同指针p1
、p2
和p3
。 - 使用
cout
和hex
标志符来以十六进制格式打印这些指针的值。
- 在
需要注意的是,这个单例模式的实现是线程不安全的。如果在多线程环境中调用 getInstance
,可能会导致多个实例被创建,因为两个线程可能同时检查 pInstance
是否为 NULL
,然后都创建一个新的实例。为了确保线程安全,通常需要在 getInstance
函数中添加同步机制,例如使用互斥锁。
此外,这个实现没有考虑 SingleInstance
类的拷贝构造函数和赋值操作符的正确实现,这在实际应用中是必要的,以确保类的正确行为和资源管理。如果类需要支持拷贝,那么需要实现拷贝构造函数和赋值操作符,并确保它们正确地管理资源。如果不需要拷贝,可以将拷贝构造函数和赋值操作符声明为 delete
。
为什么pInstance
不为NULL
?
pInstance
是一个静态成员变量,它被初始化为 NULL
。静态成员变量属于类本身,而不是类的任何特定实例。这意味着无论创建多少个类的实例,静态成员变量只有一个副本。
在 SingleInstance
类中,pInstance
被用来存储类的唯一实例的地址。当第一次调用 getInstance()
方法时,pInstance
仍然是 NULL
,因此会创建一个新的 SingleInstance
对象,并将 pInstance
指向这个新创建的对象。之后,无论调用多少次 getInstance()
方法,只要 pInstance
不为 NULL
,它就会直接返回已经存在的实例的地址,而不会再次创建新的实例。
因此,pInstance
在第一次调用 getInstance()
之后就不会为空了,它会一直保持对唯一实例的引用,直到程序结束或者在某个时刻显式地删除这个实例。
后续调用 getInstance()
方法时的行为:
在第一次调用 getInstance()
方法时,我们已经讨论了以下步骤:
- 检查
pInstance
是否为NULL
。 - 如果是
NULL
,则创建一个新的SingleInstance
对象。 - 将
pInstance
指向这个新创建的对象。 - 返回
pInstance
的值。
现在,假设我们已经完成了第一次调用,并且 pInstance
已经指向了一个有效的 SingleInstance
对象。当后续调用 getInstance()
方法时,会发生以下步骤:
-
调用
getInstance()
方法:
当后续调用getInstance()
方法时,程序会再次进入这个函数。 -
检查
pInstance
是否为NULL
:
在getInstance()
函数内部,再次检查静态成员变量pInstance
是否为NULL
。由于pInstance
已经被第一次调用时初始化,它现在指向一个有效的SingleInstance
对象,因此它不再是NULL
。 -
直接返回
pInstance
:
由于pInstance
不是NULL
,程序不需要再次执行new SingleInstance
来创建新的对象。相反,getInstance()
函数直接返回pInstance
的值,即之前创建的SingleInstance
对象的地址。 -
返回
pInstance
的值:
getInstance()
函数返回pInstance
的值,这意味着后续调用将返回同一个对象的地址。
这个过程确保了无论调用 getInstance()
多少次,都只会创建一个 SingleInstance
对象,并且所有调用都会返回这个对象的引用。这是单例模式的关键特性,它保证了全局访问点的唯一性和对象的单一实例。
总结一下,后续调用 getInstance()
方法时,由于 pInstance
已经指向了一个有效的 SingleInstance
对象,getInstance()
函数将直接返回这个对象的地址,而不会再次创建新的对象。这样,无论何时何地,只要调用 getInstance()
,都会得到同一个 SingleInstance
对象的引用。
这里是一个简化的例子来说明这个过程:
class SingleInstance {
public:
static SingleInstance* getInstance() {
if (pInstance == NULL) { //第一次调用的时候,pInstance确实=NULL,满足pInstance == NULL这个判断
pInstance = new SingleInstance; //因此会创建一个新的 SingleInstance 对象,并将 pInstance 指向这个新创建的对象
}
return pInstance;//函数getInstance()返回pInstance的值,也就是新创建的SingleInstance对象的地址
}
private:
static SingleInstance* pInstance;
SingleInstance() {
// 构造函数的实现
}
// 其他成员函数和数据成员
};
// 静态成员变量初始化
SingleInstance* SingleInstance::pInstance = NULL;
int main() {
SingleInstance* p1 = SingleInstance::getInstance(); // 创建唯一实例
SingleInstance* p2 = SingleInstance::getInstance(); // 返回已存在的实例
SingleInstance* p3 = SingleInstance::getInstance(); // 返回已存在的实例
// p1, p2, 和 p3 都将指向同一个实例
// 因此,它们的地址将是相同的
cout << hex << p1 << endl; // 打印实例的地址
cout << hex << p2 << endl; // 打印相同的地址
cout << hex << p3 << endl; // 打印相同的地址
return 0;
}
在这个例子中,pInstance
在第一次调用 getInstance()
时被初始化为指向新创建的 SingleInstance
对象。之后,无论调用多少次 getInstance()
,它都会返回同一个对象的地址。因此,pInstance
不会为空,它会一直指向同一个实例。