一.引用.
1. 引用概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器
不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空
间
类型& 引用变量名(对象名) = 引用实体;
int a = 10;
int& ra = a;(必须和引用实体是同种类型)
2. 引用特性
a. 引用在定义时必须初始化
b. 一个变量可以有多个引用
c. 引用一旦引用一个实体,再不能引用其他实体
3. ## 常引用 ##
const int a = 10;
//int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
表达式 int &i = j; 将会被编译器转化成 int *const i = &j;
const对指针和引用
①指针
常量指针定义”const int* pointer=&a”告诉编译器,*pointer是常量
,不能将*pointer作为左值进行操作。
常量引用:指向常量的引用,在引用定义语句的类型前加const,表示指向的对象是常量。也跟指针一样不能利用引用对指向的变量进行重新赋值操作。
指针常量定义”int* const pointer=&b”告诉编译器,pointer是常量
,不能作为左值进行操作,但是允许修改间接访问值,即*pointer可以修改
常量指针常量:指向常量的指针常量,可以定义一个指向常量的指针常量,它必须在定义时初始化。常量指针常量定义”const int* const pointer=&c”告诉编译器,pointer和*pointer都是常量
,他们都不能作为左值进行操作。
②引用
表达式 int &i = j; 将会被编译器转化成 int *const i = &j
;
程序决不能给引用本身重新赋值,使他指向另一个变量,因此引用总是const;所以就不存在所谓的”常量引用常量”,
只有const int & a=1
;没有:Const int const& a=1
区分const是修饰指针,还是修饰指针指向的数据——画一条垂直穿过指针声明的星号(*),如果const出现在线的左边,指针指向的数据为常量;如果const出现在右边,指针本身为常量。
4. 使用场景
a. 作为函数形参
b. 作为函数返回值注意:不能返回栈空间上的引用
5. 引用和指针的区别
相同点:底层的实现方式相同,都是按照指针的方式来实现的
不同
引用在定义时必须初始化,指针没有要求
一旦一个引用被初始化为指向一个对象,就不能再指向其他对象,而
指针可以在任何时候指向任何一个同类型对象
没有NULL引用,但有NULL指针
在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地
址*空间所占字节个数
引用自加改变变量的内容,指针自加改变了指针指向
有多级指针,但是没有多级引用
指针需要手动寻址,引用通过编译器实现寻址
引用比指针使用起来相对更安全
this指针
构造与析构
一.构造函数
1.构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时,由编
译器自动调用,在对象的生命周期内只调用一次,保证每个数据成员都有
一个合适的初始值
2①.无参构造函数和带有缺省值的构造函数都认为是缺省的构造函数,并
且缺省的构造函数只能有一个
(1)如果一个参数设定了缺省值时,其右边的参数都要有缺省值
如:int mal(int a, int b=3, int c=6, int d=8) 正确,按从右到左顺序设定默认值。
int mal(int a=6, int b=3, int c=5, int d) 错误,未按照从右到左设定默认值。c设定缺省值了,而其右边的d没有缺省值。
(2)调用时,则遵循参数调用顺序,自左到右逐个调用。
如:void mal(int a, int b=3, int c=5); //默认参数
mal(3, 8, 9 ); //调用时有指定参数,则不使用默认参数
mal(3, 5); //调用时只指定两个参数,按从左到右顺序调用,相当于mal(3,5,5);
mal(3); //调用时只指定1个参数,按从左到右顺序调用,相当于mal(5,3,5);
mal( ); //错误,因为a没有默认值
mal(3, , 9) //错误,应按从左到右顺序逐个调用
再如: void mal(int a=8, int b=3, int c=5); //默认参数
mal( ); //正确,调用所有默认参数,相当于mal(8,3,5);
重载函数与默认参数重叠导致的二义性问题:
func(int); //重载函数1,只有1个参数,无默认参数
func(int, int =4); //重载函数2,有2个参数,有1个默认参数
func(int a=3, int b=4, int c=6); //重载函数3,有3个参数,有3个默认参数
fucn(float a=3.0, float b=4.0 float c=5.0); //重载函数4,有3个参数,有3个默认参数
fucn(float a=3.0, float b=4.0 float c=5.0 float d=7.9 ); //重载函数5,有4个参数,有4个默认参数
func(2); //可调用前3个函数,出现二义性
func(2.0); //可调用后2个函数,出现二义性
所以当重载函数与默认参数共同使用时,要注意出现二义性问题。
**3.初始化列表
类中包含以下成员,一定要放在初始化列表位置进行初始化:
引用成员变量
const成员变量
类类型成员(该类有非缺省的构造函数)
**
class CExample {
public:
int a;
float b;
//构造函数初始化列表
CExample(): a(0),b(8.8)
{}
//构造函数内部赋值
CExample()
{
a=0;
b=8.8;
}
};
3.初始化和赋值对内置类型(就是基本数据类型)的成员没有什么大的区别,像上面的任一个构造函数都可以.
上面的构造函数(使用初始化列表的构造函数)显式的初始化类的成员;
而没使用初始化列表的构造函数是对类的成员赋值,并没有进行显式的初始化.当一个类中有非内置类型成员变量时,若没有显示初始化这个非内置类型成员变量,那么编译器会隐士调用该非内置类型成员变量的默认构造函数,而如果用了成员初始化构造函数,对这个变量有了显示初始化,系统就不会再隐士调用它的默认构造函数了,所以这里少了一次构造。
class Food
{
public:
Food(int type = 10)
{
m_type = 10;
}
Food(Food &other) //拷贝构造函数
{
m_type = other.m_type;
}
Food & operator =(Food &other) //重载赋值=函数
{
m_type = other.m_type;
return *this;
}
private:
int m_type;
};
(1)构造函数赋值方式 初始化成员对象m_food
class Dog: public Animal
{
public:
Dog(Food &food)
//:m_food(food)
{
m_food = food; //初始化 成员对象
}
private:
Food m_food;
};
//使用
Food fd;
Dog dog(fd); //
Dog dog(fd);结果:
先执行了 对象类型构造函数Food(int type = 10)——>
然后在执行 对象类型构造函数Food & operator =(Food &other)
?
(2)构造函数初始化列表方式
class Dog: public Animal
{
public:
Dog(Food &food)
:m_food(food) //初始化 成员对象
{
//m_food = food;
}
private:
Food m_food;
};
//使用
Food fd;
Dog dog(fd); //
Dog dog(fd);结果:执行Food(Food &other)拷贝构造函数完成初始化
二.析构函数
1.析构函数:与构造函数功能相反,在对象被销毁时,由编译器自动调用,完成类的一些资源清理和汕尾工作.
析构函数在类名(即构造函数名)加上字符~
析构函数无参数无返回值
一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省
的析构函数
对象生命周期结束时,C++编译系统系统自动调用析构函数
注意析构函数体内并不是删除对象,而是做一些清理工作
运算符重载和友元
一.重载操作符
1. 概念
重载操作符是具有特殊函数名的函数,关键字operator后面接需要定义的
操作符符号。操作符重载也是一个函数,具有返回值和形参表。它的形参
数目与操作符的操作数目相同,使用运算符重载可以提高代码的可读性
返回值 operator 操作符(参数列表)。
就像一个词在不同的场景下有不同的含义
2. 注意
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型或者枚举类型的操作数
用于内置类型的操作符,其含义不能改变,例如:内置的整型+,
能改变其含义
作为类成员的重载函数,其形参看起来比操作数数目少1成员函数的
操作符有一个默认的形参this,限定为第一个形参.
一般将算术操作符定义为非成员函数,将赋值运算符定义成员函数
操作符定义为非类的成员函数时,一般将其定义为类的友元
== 和 != 操作符一般要成对重载
下标操作符[]:一个非const成员并返回引用,一个是const成员并
返回引用
解引用操作符*和->操作符,不显示任何参数
前置式++/–必须返回被增量或者减量的引用,后缀式操作符必须返
回旧值,并且应该是值返回而不是引用返回
输入操作符>>和输出操作符<<必须定义为类的友元函数