一、const
- 修饰常量,比如
const int a = 10
,说明该变量无法被修改 - 修饰指针,包括指向常量的指针和指针常量
指向常量的指针:const int *p = &a
; 无法通过指针修改其所指变量的值(可以指向const 和 非const)
指针常量:int *const p = &a
; 不能修改指针中保存的地址 - 常量引用,避免拷贝,同时无法通过函数对值修改
void fun(const int &a,const int &b);
常量引用可以用任意表达式、字面值、可类型转换的对象初始化 - 修饰函数
常成员函数无法修改类中的数据成员int getValue() const;
二、static
- 修饰普通变量
– 生命周期:main 函数之前分配,程序结束释放
– 存储区域:全局区 - 修饰普通函数
– 作用范围:定义该函数的文件内才可以使用,防止与他人重名 - 静态成员变量:
– 静态成员变量是该类的所有对象共有,只分配一次内存,该类所有对象共享访问更新
– 存储在全局区,属于类,不属于特定对象,不占用对象内存
– 只能在类体外初始化,且必须初始化,初始化时分配内存
– 生命周期:编译时分配,程序结束释放
– 访问形式:<类对象名>.<静态数据成员名> <类类型名>::<静态数据成员名>
//Example 5
#include <iostream.h>
class Myclass
{
public:
Myclass(int a,int b,int c);
void GetSum();
private:
int a,b,c;
static int Sum;//声明静态数据成员
};
int Myclass::Sum=0; //定义并初始化静态数据成员
Myclass::Myclass(int a,int b,int c)
{
this->a=a;
this->b=b;
this->c=c;
Sum+=a+b+c;
}
void Myclass::GetSum()
{
cout<<"Sum="<<Sum<<endl;
}
void main()
{
Myclass M(1,2,3);
M.GetSum();
Myclass N(4,5,6);
N.GetSum();
M.GetSum();
}
- 静态成员函数
– 属于类本身,不作用与对象,不具有 this 指针,因此只能访问静态成员变量和静态成员函数
– 出现在类体外的函数定义不能指定关键字static
– 调用方法:成员访问操作符(.)和(->) <类名>::<静态成员函数名>(<参数表>)
//Example 6
#include <iostream>
using namespace std;
class Student{
private:
char *name;
int age;
float score;
static int num; //学生人数
static float total; //总分
public:
Student(char *, int, float);
void say();
static float getAverage(); //静态成员函数,用来获得平均成绩
};
int Student::num = 0;
float Student::total = 0;
Student::Student(char *name, int age, float score)
{
this->name = name;
this->age = age;
this->score = score;
num++;
total += score;
}
void Student::say()
{
cout<<name<<"的年龄是 "<<age<<",成绩是 "<<score<<"(当前共"<<num<<"名学生)"<<endl;
}
float Student::getAverage()
{
return total / num;
}
int main()
{
(new Student("小明", 15, 90))->say();
(new Student("李磊", 16, 80))->say();
(new Student("张华", 16, 99))->say();
(new Student("王康", 14, 60))->say();
cout<<"平均成绩为 "<<Student::getAverage()<<endl;
return 0;
}
三、this 指针
- 非静态成员函数的隐含的特殊指针,指向调用函数的对象
- 隐含申明为指针常量:
CLassName *const this
- 特殊:在常成员函数中,this 指针类型为指向常对象的指针常量
const ClassName *const
,故常成员函数无法修改数据成员 - 不能
&this
- 某些情况需要显示引用 this 指针
四、inline 内敛函数
- 相当于把函数的内容在调用函数处展开
- 内敛函数一般比较简单,不包括循环,递归等
- 有类内隐式内敛,类外显示内敛
- 优点:
– 提高程序运行速度,因为省去压栈和弹栈
– 相比宏函数,多了安全检查和自动类型转换 - 缺点:
– 代码膨胀
– inline 函数改变后需要重新编译
– 是否内敛取决于编译器
虚函数和内敛函数(后续更新)
五、volatile
- volatile 关键字是类型修饰符
volatile int i = 10
, 它告诉编译器不要对这样的对象进行优化,每次从稳定的地址进行访问。
volatile int i=10;
int a = i;
...
// 其他代码,并未明确告诉编译器,对 i 进行过操作
int b = i;
比如上述代码,如果编译器发现两次 i 的读取过程中并未对 i 的值进行修改,会自动把上次的值放在 b 中,这样如果 i 是寄存器数据或者端口变量容易出错。
比如在定时器中断中的变量在中断外引用时容易出现此类问题,需要加volatile关键字(PPT补充)
六、assert()
- assert() 是宏,非函数
- 作用是如果条件返回错误,则终止程序执行
assert(p != nullptr)
- 可以在
#include<assert.h>
#include<cassert>
之前定义NDEBUG
来关闭
#define NDEBUG
#include <assert.h>
assert(p != null) //不起作用
七、sizeof
- 对数组,得到整个数组所占空间大小
- 对指针,得到指针本身所占空间大小,32位机器,指针占4个字节;64位机器,指针占8个字节
八、#pragma pack(n)
- 自然对齐:变量的内存地址正好位于其长度的整数倍,这样有利于提高存取速度
- 通过
#pragma pack(n)
可以强制结构体、联合体及类成员变量以 n 字节对齐方式存取
struct s {
char ch;
int i;
};
如果 sizeof(struct s)
, 则结果为8,因为默认自然对齐,char 占用一个字节,int 的地址需要被 4 整除,所以需要在 char 后添加 3 个空字节,所以一共是 8 个自己。
#pragma pack(push) // 保存对齐状态
#pragma pack(1) // 设定为 1 字节对齐
struct s {
char ch;
int i;
};
#pragma pack(pop) // 恢复对齐状态
这样可以强制结构体数据连续排列,节省资源,但速度减慢
九、位域
- 数据在存储时占用一位或几位二进制,通常通过结构体申明
下述代码表明申请 4 bit 的空间,由于小于unsigned int
的空间长度,故data
共占用 4 字节的空间
struct
{
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
unsigned int d:1;
}data;
- 位域的存储依然遵守编译器自然对齐的原则,故下述代码的中 data 占用 8 个字节
struct data
{
unsigned a:12;
unsigned b:24;
unsigned c:6;
};
转载:https://blog.csdn.net/Suqing_2018/article/details/104521199
查看评论