目录
1.引用
1.1引用特性:
1.2 传引用传参
1.3 引用返回
2. 重要注意事项
3.函数重载
3.1 重载原理
4. 类的认识
4.2 访问限定符号
4.3 类的作用域
4.4 类的实例化
5.对象
6. this指针
6.1 特性
6.2 注意事项
1.引用
相当与给某个变量取了一个别名,但是这前者和后者之间的地址是相同的。
发现: k的值修改会影响a,而j的修改不会。
1.1引用特性:
1.引用在定义时必须初始化
2.一个变量可以有多个引用
3.引用一旦引用一个实体,则不能再引用其他实体
1.2 传引用传参
对于一个函数,引用传参时候:形参的修改可以影响到实参。
以Swap交换函数为例子:
void Swap(int& a,int& b){ int tmp=a; a=b; b=tmp;}
如此就算不使用指针,也能够实现数值的交换,并且效率更高。
1.3 引用返回
首先我们需要知道:申请空间,实际上相当于向系统讨要空间的使用权,同样
销毁空间,就是系统将空间的使用权收回去。
上图是我们一般见到的传值返回,返回的值是在栈帧销毁前先存储在一个临时变量中,然后再值拷贝到主函数中的a中。
传引用返回:会返回n的别名,效率更快。
除此之外,传引用返回可以修改返回的值 :
Count()++后值被修改。
2. 重要注意事项
如果函数返回时,出了函数作用域,如果返回对象还在(即对应空间还没还给系统),则可以使用引用返回;如果已经空间使用权还给了系统,则必须使用传值返回。
对于编译器而言,已经销毁(归还了使用权)的栈帧,有可能会清理原来的空间,也有可能不清理,所以原来的空间已经不安全。这样就导致返回了别名也没有意义,因为原来的空间可能会被清理掉。
3.函数重载
函数重载概念: 函数重载:是函数的一种特殊情况, C++ 允许在 同一作用域中 声明几个功能类似 的同名函数 ,这 些同名函数的形参列表 ( 参数个数 或 类型 或 类型顺序 ) 不同 ,常用来处理实现功能类似数据类型不同的问题。
//参数类型不同int Add(int left, int right);double Add(double left, double right);//函数参数数量不同void f1(int a);void f1(int a,int b);//函数参数类型顺序不同void f(int a, char b);void f(char b, int a)
3.1 重载原理
c++的名字修饰(name Mangling)
简单的说就是G++环境下编译代码的时候,会给符合重载的函数的名字给予修饰,从而就能够分辨两者,分别进行调用(Windos下的修饰过于复杂,这里就不多解释,感兴趣可以详细了解)
4. 类的认识
class className { // 类体:由成员函数 和 成员变量组成 }; // 一定要注意后面的分号class 为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面 分 号不能省略 。 类体中内容称为类的成员: 类中的 变量 称为 类的属性 或 成员变量 ; 类中的 函数 称为 类的方法 或者 成员函数 。 类与之前C语言结构体有一个最大的区别:类中可以定义函数,并且如果函数直接在类的内部定义,编译器可能将其当作内联函数。
以日期类为例子:
class Date{public:Date(int year = 2023, int month = 1, int day = 1){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;}
注意:
一般内联函数都是代码量比较小的函数,因为失去了call调取指令地址,取而代之的是直接展开,如果函数太庞大,无疑会在运行时造成更多负担。
4.2 访问限定符号
如果在没有自主划分的情况下:class默认访问权限为私有,struct默认访问权限为公有
(1)public(公有):类内类外都可以访问。
(2)protected(保护):类内可以访问,类外不能访问。
(3)private(私有):类内可以访问,类外不能访问(一般通过成员函数访问)
4.3 类的作用域
类会定义一个新的作用域。类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
如:
class Person{public: void PrintPersonInfo();private: char _name[20]; char _gender[3]; int _age;};// 这里需要指定PrintPersonInfo是属于Person这个类域void Person::PrintPersonInfo(){ cout << _name << " "<< _gender << " " << _age << endl;
4.4 类的实例化
用类类型创建对象的过程,称为实例化。
1.类是对对象经行描述的,交代了有哪些成员,但是定义一个类本身并没有分配实际的内存空间来储存。
2.并且一个类可以实例化多个对象,对象会占用真正的物理空间,存储类成员的变量
//以上述日期类为例子int main(){Date d1;//实例化Date d2;return 0;}
5.对象
类对象的存储方式:只保存成员变量,成员函数存放在公共的代码段(这里虽然说存放在代码段,但是成员函数调用的时候依旧是在栈上创建栈帧)
所以对象大小的计算:一个类对象的大小,实际就是该类中成员变量的大小之和。
空类的大小比较特殊,编译器给了空类一个字节来标识这个类的对象。
6. this指针
我们先来看一个例子:
class Date{ public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } void Print() { cout <<_year<< "-" <<_month << "-"<< _day <<endl; }private: int _year; // 年 int _month; // 月 int _day; // 日};int main(){ Date d1, d2; d1.Init(2022,1,11); d2.Init(2022, 1, 12); d1.Print(); d2.Print(); return 0;}
我们需要去分别给Date类型对象d1,d2分别赋值(这里不叫初始化,后面会提到原因),但是我们回顾学c语言的结构体时候,当初始化一个结构体的时候,要把结构体的地址传到函数里面,但是这里却没有传这个地址,那么函数是怎样给成员赋值的呢?
答案就是this指针,实际上代码是这样:
class Date{ public: void Init(Date*this,int year, int month, int day) { this->_year = year; this->_month = month; this->_day = day; } void Print(Date *this) { cout << this->_year<< "-" << this->_month << "-"<< this->_day <<endl; }private: int _year; // 年 int _month; // 月 int _day; // 日};
6.1 特性
1.this指针的类型是*const,所以在成员函数中不能给this指针赋值
2.this本质上是"成员函数"的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针
3.this是一个隐含的指针形参,有编译器自动传递,不需要用户传递
6.2 注意事项
this指针在特定情况下可以为空:
当成员函数中没有实际对this指针解引用时,this可以为空。