一.类的static成员
对于用static修饰的成员函数,称为静态成员函数;用static修饰的成员变量,称为静态成员变量.
如果对于一个成员,对其以static修饰,此时这个成员就不再属于对象(求类的大小时,不计算静态成员变量),而是属于这一整个类的所有对象.因为静态成员的生命域不在类中,而是在静态区,所以静态的成员只能在类外初始化.
特性:
- 静态成员为所有类对象所共享,不属于某个具体的实例
- 静态成员变量必须在类外初始化,初始化时不添加static关键字
- 类静态成员即可用类名::静态成员 或者 对象.静态成员/引用.静态成员/指针.静态成员来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员和类的普通成员一样,也有public,protected,private3种访问级别,也可以具有返回值
- 静态成员和全局变量虽然都存储在静态区,但是静态成员的生命周期只在本文件中,而全局变量不是
因为静态成员函数不属于某个对象,所以它没有this指针,无法访问任何非静态的成员,但是非静态的成员函数具有this指针,可以访问静态的成员。
静态成员与普通成员的对比:
- 普通数据成员属于类的一个具体的对象,只有对象被创建了,普通数据成员才会被分配内存.而静态数据成员属于整个类,即使没有任何对象创建,类的静态数据成员变量也存在
- 因为类的静态数据成员的存在不依赖任何对象的存在,类的静态数据成员应该在代码中被显式的初始化,一般要在类外进行.
- 外部访问类的静态数据成员能直接通过类名来访问,虽然静态成员不属于类的某个对象,但是仍然可以使用类的对象,引用或者指针来访问静态数据成员
- 类的静态数据成员函数无法直接访问普通数据成员(可以通过对象名间接的访问),而类的任何成员函数都可以访问类的静态数据成员
类外调用静态成员的几种方式:
class A {
public:
A() {
cout << "构造函数" << endl;
}
static void num() {
cout << "静态成员函数" << endl;
}
~A() {
cout << "析构函数" << endl;
}
};
int main() {
A a;
A* b = new A();
A& a1 = a;
//调用静态成员函数的几种方式:
A::num(); //类名::静态成员函数
a1.num(); //引用.静态成员函数
a.num(); //对象.静态成员函数
b->num(); //指针.静态成员函数
delete b;
return 0;
}
二.类的const成员
需要const的原因:
因为对于类和对象,封装性是一个很重要的东西,但是访问限定符只对外部有影响,对自身的成员函数没有影响,如果我们不想让一个成员函数对类的成员进行修改,这时,就需要用const来修饰成员函数。
class Date
{
public:
//等价于 void print(const Date* this)
void Print() const
{
cout << _year << '-' << _month << '-' << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
对于用const修饰的成员函数,需要将const放在最后面,来区分开const参数和const返回值。这里的const其实修饰的是该成员函数的this指针,所以该成员函数就无法对类的成员进行修改。
提出问题:
1.const对象可以调用非const成员函数吗?
答案:不可以,因为const对象只能读不能写(不能修改),而非const成员函数则可读可写,使
权限放大了,则不可以.
2.非const对象可以调用const成员函数吗?
答案:可以,因为非const对象可读可写(可以修改),const成员函数只可读,使权限缩小,则可以.
3.const成员函数内可以调用其它非const成员函数吗?
答案:不可以,因为const成员函数的this指针是常量,只可读,而非const的成员函数则可读可写,使权限放大了,不可以.
4.非const成员函数内可以调用其它的const成员函数吗?
答案:可以,因为非const成员函数的this指针可读可写,const成员函数只可读,使权限缩小,则可以。
三.常量指针与指针常量
常量指针:是指执行的内容是常量
const int *n;
int const *n;
注意:
- 常量指针说的是不能通过这个指针修改变量的值,但是可以通过其他的引用来改变变量的值
int a = 5;
const int *p = &a;
a = 6; //修改成功
- 常量指针指向的值不能改变,但是并不是意味着指针本身不能改变,常量指针可以指向其它的地址.
int a = 5;
int b = 6;
const int* n = &a;
n = &b;
指针常量:是指指针本身是个常量,不能改变指针的指向.
int* const n;
- 指针常量指向的地址不能改变,但是地址中的数值是可以改变的
区分:常量指针和指针常量的关键在于星号的位置,以星号为分界线
- 如果const在星号的左边,则为常量指针
- 如果const在星号的右边,则为指针常量
指向常量的常指针:指针指向的位置不能改变且不能通过这个指针改变变量的值.(但是仍然可以通过其他的普通指针改变变量的值)
const int* const p;
const指针和指向常量的指针几种易混淆的用法:
const int p; int 型常量
const int *p; p是一个指向int型常量的指针(指针指向的值不能变)
int const *p; p是一个指向int型常量的指针(指针指向的值不能变)
int* const p; p是一个指向int的const指针 (指针指向的地址不能变)
const int* const p; p是一个指向int型常量的const指针(指向的值与指针指向的地址均不能变)
int const * const p; p是一个指向int型常量的const指针(指向的值与指针指向的地址均不能变)
四.volatile关键字
volatile关键字提醒编译器所定义的变量随时有可能会改变,因此编译后的程序每次需要存储或者读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储,可能使用寄存器中的值.
不让编译器进行优化,到内存中读取数值,而不是在寄存器中读取数值.