1.指针是一个变量,本身占内存(32/64位),这段内存里的数据为一个地址;引用跟原来的变量为同一个东西,编译器层面的别名
2.有const指针,没有const引用(本身变不可修改指向和指向地址的内容)
3.指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
4.指针的值可以为空,但是引用的值不能为nullptr,并且引用在定义的时候必须初始化
5.指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了
6."sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小
7.指针和引用的自增(++)运算意义不一样;
栈:自动,申请快,根据系统,通常较小,使用过多会溢出;
堆:手动,申请慢,内存条大小,链表->内存碎片;
new底层调用 :
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{ // try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{ // report no memory
_THROW_NCEE(_XSTD bad_alloc, );
}
return (p);
}
简单类型直接调用operator new分配内存,复杂类型还要再执行构造函数;
通过new_handler来处理new失败的情况;
new分配失败的时候不像malloc那样返回NULL,直接抛出异常;要判断是否分配成功应该用异常捕获的机制;
delete底层调用:
void operator delete( void * p )
{
RTCCALLBACK(_RTC_Free_hook, (p, 0));
free( p );
}
复杂类型还需先执行析构函数;
new/delete底层还是最终执行了malloc/free;对于new[]/delete[],复杂类型还会额外记录数组大小
同异:
从语法上来讲,class和struct做类型定义时只有两点区别
大部分class有的,struct也可以实现
const变量必须在定义时初始化,而且类中的const变量必须在初始化列表中初始化;
const在编译阶段起作用,可以进行调试。#define在预编译阶段起作用,简单替换,不能进行调试
const有类型检查,#define无类型检查,const安全程度高
编译器不为const变量分配空间而是将其存储在符号表中读取效率高占用内存少,define每次用到都要分配空间,占用内存大,效率低
const不能被重新定义,而#define可以通过#unde后进行重新定义
#define还可以用来防止头文件被重复包含问题
const:
1.修饰指针 *;在 *号前表示指针指向的地址中的值不能修改;在 *号后表示指针指向的地址不能修改
2.修饰函数返回值;则这个函数返回值作为左值时编译会报错(相关内容:函数返回值的引用)
3.修饰类;类中const成员变量与普通const变量区别不大;初始化 const 成员变量只能通过参数初始化表;const成员函数不能修改任何成员变量;const 对象在该对象生命周期内,必须保证没有任何成员变量被改变,const对象只能调用const成员函数。
static:
1.修饰非类成员;隐藏、全局生存期(早于main函数,静态存储区,默认值为0)
2.修饰类成员变量;在类中的静态数据成员变量属于类共享,即使没有定义对象,静态成员也存在,静态数据成员在类中说明,在类外定义、初始化,并分配内存空间,一经定义则必须初始化,可以通过对象去访问静态成员,类名::静态成员,整个程序的生命周期
3.修饰类成员函数;静态成员函数属于一个类而不是某个对象(没有this指针),不能是虚函数,不能直接访问非静态成员变量( 虚函数和非静态成员变量是对象创建的时候才会有的)
1.static成员变量(非const)必须在类外定义,在类中只是作为声明,不能使用类初始化成员列表来初始化,只能在定义的时候初始化;const的成员变量必须在类中定义的时候就初始化,不能在类外再定义,不能使用类初始化成员列表初始化。
2.static 与 virtual不能共存于一个函数上,即没有静态虚函数,原因在于静态函数没有this指针,无法通过对象实例来调用,而虚函数与普通成员函数一样必须通过this指针来调用。但是static成员可以通过类实例或类来调用,即“A a;a.b”或“A::b”都可。
4.非static的const成员,和引用类型的成员,因为在定义的时候就必须初始化,所以必须使用类初始化成员列表来初始化。
5.在一个函数的最后加上const,则这个函数只能是一个成员函数,而且是非静态的。因为const的函数就隐含着“this指针所指的对象不能被修改”这个意思。同时,const函数不能对任何成员函数做赋值等修改的动作,而且如果一个实例是const实例,这个实例只能调用const函数。
6.static成员在编译的时候就已经确定了(未显式初始化的则为0)。而普通成员则在创建实例的时候初始化。
故一个类对象里面的成员的初始化顺序:
程序加载时确定:
a.静态成员变量的空间及值。
b.成员函数的空间及地址。
创建对象时(运行时)确定:
c.虚函数表(如果该类或该类的任一个基类,超类有虚函数)
e.普通成员变量的空间及值。
通常一个类的某些属性会被定义为私有变量以达到保护和隐藏的目的,但是恰好外部需要获取这个变量的值时,可以使用const成员函数返回私有变量的值,可读不可写。
其实就是const指针和指针const
const int *p1;//等价int const *p1; 底层const
int * const p1;//顶层const
主要记住,const右边先是*号还是先是变量名,哪个先就限定哪个
override用于当一个继承自A类的B类需要重写A类的函数时,显示的告诉编译器,该函数为“继承重写”;防止由于笔误等情况,将fun();写成fnu();导致并没有重写而是产生了一个新函数的情况。
final类似java中,用于当一个类或者一个函数不想再被其他类继承或继承后重写时,显示的告诉编译器不可继承或重写;
举个例子,java中的string类是由fianl修饰的,不可继承,而c++早期没有final,string类可以继承,这就导致了*************