文章目录
- 一、this指针
- (一)概念
- (二)显式使用this指针的场景
- 1. 当形参和成员变量名一致时
- 2. 返回对象自身的时候必须要使用this指针
- 3. 在类中销毁一个对象
- 二、常函数和常对象
- (一)常函数
- 1. 概念
- 2. 语法格式
- (二)常对象
- 1. 概念
- 2. 语法格式
- (三)使用示例
- 三、静态成员
- (一)静态成员变量
- 1. 概念
- 2. 语法格式
- 3. 调用静态成员变量的方式
- (二)静态成员函数
- 1. 概念
- 2. 语法格式
- 3. 调用静态成员函数的方式
一、this指针
(一)概念
this指针是隐藏在类的成员函数中的一个隐藏的形参,就是this指针
this指针指向对象的自身。类型是类类型
- 注:
- this指针不能显式的出现在形参表中
- this指针不能显式的出现在初始化列表中
- this指针指向对象的自身
- this指针只能出现在类中
- this是C++中的关键字
- 类中的成员变量本质上就是通过this指针指向的,但是可以省略不写
(二)显式使用this指针的场景
1. 当形参和成员变量名一致时
不仅可以使用初始化参数列表,还可以使用this指针
#include <iostream>using namespace std;class A{
public:A(int m_a,int m_b){this->m_a = m_a;this->m_b = m_b;}void print(){cout<<"m_a="<<m_a<<" m_b="<<m_b<<endl;}
private:int m_a;int m_b;
};int main()
{A a(10,20);a.print();return 0;
}
2. 返回对象自身的时候必须要使用this指针
#include <iostream>using namespace std;class A{
public:A(int m_a,int m_b){this->m_a = m_a;this->m_b = m_b;}A& add(){m_a++;m_b++;return *this; //返回对象自身}void print(){cout<<"m_a="<<m_a<<" m_b="<<m_b<<endl;}
private:int m_a;int m_b;
};
int main()
{A a(10,20);a.print();a.add();a.print();a.add().add().add();a.print();return 0;
}
输出结果:
3. 在类中销毁一个对象
#include <iostream>using namespace std;class A{
public:A(int m_a,int m_b){this->m_a = m_a;this->m_b = m_b;}void print(){cout<<"m_a="<<m_a<<" m_b="<<m_b<<endl;}void destory(){delete this;}
private:int m_a;int m_b;
};
int main()
{A a(10,20);a.print();a.destory();return 0;
}
二、常函数和常对象
(一)常函数
1. 概念
常函数又称为常成员函数,用const修饰的成员函数叫做常函数。
- 注:
- const是用来修饰this指针;
- 常函数中不能对成员变量进行修改
- 如果要对常函数中成员变量进行修改,需要将成员变量用
mutable
进行修饰,但是一般不这样使用
2. 语法格式
普通函数:
返回值类型 函数名(形参表){ ... }
常函数:
返回值类型 函数名(形参表) const { ... }
- 注:
- 常函数版本和非常函数版本构成重载关系,如果同时出现,优先调用非常函数版本,如果没有非常函数版本,才会调用常函数版本
(二)常对象
1. 概念
用const修饰的对象就是常对象
2. 语法格式
const 类名 对象名;
- 注:
- 如果对象是常对象只能调用常函数版本;
- 如果对象是非常对象,则会优先调用非常函数版本,如果没有非常函数版本,才会调用常函数版本
(三)使用示例
#include <iostream>
using namespace std;
class Myclass{
public:Myclass(int a,int b):m_a(a),m_b(b){}//非常函数版本void print(){cout<<"非常函数版本"<<endl;cout<<"m_a="<<m_a<<" m_b="<<m_b<<endl;}//常函数版本void print()const{cout<<"常函数版本"<<endl;cout<<"m_a="<<m_a<<" m_b="<<m_b<<endl;}
private:int m_a;int m_b;
};int main()
{Myclass m(10,20);m.print(); //有非常函数版本优先调用非常函数版本cout<<"---------------------"<<endl;const Myclass n(100,200);n.print();return 0;
}
输出结果:
常对象会调用常函数版本,非常函数会调用非常函数版本
如果没有非常函数版本的函数,非常对象也会调用常函数版本:
如果没有常函数版本,常对象调用非常函数版本会报错
三、静态成员
用static
修饰的成员为静态成员
静态成员分为静态成员变量和静态成员函数
(一)静态成员变量
1. 概念
用static
修饰的成员变量为静态成员变量
2. 语法格式
//静态成员变量的声明
class 类名{
访问控制权限:static 数据类型 变量名;
}
//静态成员变量的定义
数据类型 类名::变量名 = 初始值;
- 注:
- 静态成员变量是受访问控制权限进行控制的;
- 静态成员变量必须在类外进行定义,类内只能声明;
- 静态成员变量在类外定义的时候不用加static修饰,需要在变量名前加上“
类名::
” - 静态成员变量不占类的内存空间,属于全局域,只在类中声明;
不实例化对象也可以访问到静态成员变量
3. 调用静态成员变量的方式
- 访问栈区对象
类名 对象名;
对象名.静态成员变量;
- 访问堆区对象
类名 *对象名 = new 类名;
对象名->静态成员变量;
- 不实例化对象进行访问
类名::静态成员变量;
#include <iostream>
using namespace std;
class Myclass{
public://static int m_s = 200; //类内只能声明,不能定义static int m_s; //类内声明
private:static int m_a;int m_b;
};int Myclass::m_s=100; //类外定义
int Myclass::m_a=200;
int main()
{//堆区对象Myclass m;cout<<"m.m_s="<<m.m_s<<" |&m.m_s="<<&m.m_s<<endl;m.m_s=200;//cout<<"m.m_a"<<m.m_a<<endl; //静态成员变量受访问控制权限控制//栈区对象Myclass *mm = new Myclass;cout<<"mm->m_s="<<mm->m_s<<" |&mm->m_s="<<&(mm->m_s)<<endl;mm->m_s=300;//不实例化对象进行访问cout<<"Myclass::m_s="<<Myclass::m_s<<endl;return 0;
}
输出结果:
- 注:静态成员变量不属于类,因此无论是堆区对象还是栈区对象,它访问静态成员变量访问的都是同一块内存空间。
(二)静态成员函数
1. 概念
用static
修饰的成员函数为静态成员函数
- 注:
- 不属于类,属于全局域,不占用类的内存空间;相当于只是在类里声明了一下
- 静态成员函数受访问控制权限的限制,一般设置为public
- 静态成员函数既可以在类内声明,类外实现,也可以在类内声明,类内实现
- 在类外实现静态成员函数的定义时,不需要加static关键字,但是需要作用域的限定符
类名::
2. 语法格式
class 类名{
public:static 返回值类型 函数名(); //静态成员函数声明
}//在类外实现静态成员函数
static 返回值类型 类名::函数名(){}
- 注:
- 如果静态成员函数访问静态成员变量直接访问即可;
- 如果静态成员函数访问非静态成员变量时需要在静态成员函数的形参表中添加一个类类型的形参,之后通过该形参进行访问
- 静态成员函数不能写成常函数:因为静态成员函数没有this指针
static void func()const(){} //错误的写法
常函数相当于是在给this指针加const,而静态成员函数不属于类,没有this指针
3. 调用静态成员函数的方式
- 实例化栈区对象
- 实例化堆区对象