摘要:
近期回顾、复习C++的一些笔记,记录了C++中比较重要的一些知识点,方便日后自己查缺补漏(未记录基础语法等基础部分),分享于此希望也能帮助到大家解决有关C++部分的疑问。
适合人群:有C/C++基础,想要进一步巩固自己C++知识体系的筒子
C++知识真的好杂,感觉总是在打破自己定义的规则,硬着头继续学!
小建议:有的问题,站在编译器的角度去考虑往往就更好理解。
注:PDF版本文章底部自取
面向对象的三大特性:封装
、继承
和多态
封装
:可以实现类对部分成员和方法进行隐藏,只暴露想要暴露的细节。 -把变量(属性)和方法(操作)合成一个整体,封装在一个类中
-对变量和方法进行访问控制[设置权限]
继承
:类与类之间的关系,作用是可以避免公共部分代码的重复开发,减少代码和数据冗余
多态
:即“一个接口有多种方法[形态]",程序运行时才决定调用的函数
命名空间namespace
作用及注意点
C语言通过static
关键字来控制标识符
只得在当前源文件可见,C++还可以通过namespace
命名空间实现。
命名空间通常解决在多人合作过程种出现的标识符重复问题。
注意:
命名空间只能写在全局中
命名空间可以进行嵌套
命名空间是开放的,可随时加入,但加入后的成员作用域在其加入后
namespace A{ int a; } //在命名空间A中加入int c; namespace A{ int c;//在此之后,命令空间A中的c才能被使用 }
通过作用域运算符
::
来访问不同命名空间A::cd
的成员
::
作用域运算符也可以解决、局部变量与全局变量的重名问题//全局变量 int a = 10; void test(){ int a = 20;//局部变量 cout << "局部变量a:" << a << endl;//打印局部变量a cout << "全局变量a:" << ::a << endl;//打印全局变量a }
匿名命名空间作用
namespace { int a; //相当于static int a; } //限制其只能在本文件被使用
可以取别名
namespace newname = oldname; cout<<newname::a<<endl;
一个.h文件下有两个命名空间,且具有相同的成员时,在.c文件使用或定义时,需要加上作用域符
::
不然会出现链接问题如:无法解析的外部命令
using 声明 与 编译指令
using声明:让命名空间中某个标识符直接使用,但同时也可能造成二义性
namespace A{
int a;
int b;
}
void test(){
//using是可以让命名空间中某个标识符直接使用
using A::a;
cout<<a<<endl;//using声明后可以直接使用
int a = 10; //错误语句!!!同名冲突
}
注意:如果命名空间包含一组用相同名字重载的函数,using声明就声明了这个重载函数的所有集合。
using 编译指令:让命名空间中的所有标识符都可以直接使用
namespace A{
int a = 1;
int b;
}
namespace B{
int a = 2;
int b;
}
void test(){
//using 编译指令
using namespace A;
cout<<a<<endl;//可以直接使用,打印1
int a = 10; //此时不会冲突!
//相当于命名空间中的a为全局变量,此处的为局部变量,覆盖了全局变量a,不会冲突
cout<<a<<endl;//打印10
}
void test2(){
using namespace A;
using namespace B;
cout<<a<<endl;//错误!!此时又会冲突了,不知道调用A还是B的成员a
}
struct
类型的加强
- C中定义结构体变量需要加上
struct
关键字,C++不需要。- C中的结构体只能定义成员变量,不能定义成员函数。C++即可以定义成员变量,也可以定义成员函数。
struct a{
char c;
int dd;
};//此时没有分配空间
a my_a{'a',10};//此时分配空间了
C语言中const
修饰的全局变量不能直接修改,也不能间接修改,但修饰的局部变量不能直接修改,可以间接修改。修饰的全局变量具有外部链接属性,即可以extern const int a
使用。
C++中的编译器可能会在编译阶段优化const
的变量,从而提高效率。修饰的全局变量具有内部链接属性,只能在本文件内使用。
const int a = 10;//在c++中没有内存
const int b = 20;
int * p = (int*)&bb;//进行了取址,所以有空间
*p = 200;
cout<<"b:"<<b<<endl;//打印20 因为编译器进行了优化,等价于 cout<<"b:"<<20<<endl,即发生了常量折叠
//如果不想被优化,需要加上volatile修饰,或者用变量给const修饰的局部变量赋值
cout<<"*p:"<<*p<<endl;//打印200
//两者地址是一样的
cout<<"b地址:"<<&b<<endl;
cout<<"p指向的地址:"<<p<<endl;
尽量用const
代替#define
,不是一定要,是尽量
- #define没有数据类型,
const
修饰的变量有数据类型,会进行类型检查const
有作用域,而#define不重视作用域,默认定义处到文件结尾,不能限定常量的作用范围。宏常量可以有命名空间吗?
引用(非常重要!)
语法:type &ref = val
,此处的&
不是取地址操作符,起的是标识作用 [引用是什么?–给空间取别名]
本质:内部实现是一个常指针
type * const ref = &val
[即不能改变指针指向],因此引用所占用的空间大小与指针相同
使用场景:
- 作为函数参数传递数据,节约空间
- 作为函数返回值,但是注意不要返回局部变量的引用 [因为局部变量在函数结束后内存会被回收]
注意:
- 必须在声明引用变量时进行初始化
- 初始化后不能改变
- 不能有NULL引用,必须确保引用是和一块合法的存储单元关联
- 如果函数当左值,那么该函数必须返回引用**[针对使用场景的第2条]**
建立数组的引用:
int arr[] = {1,2,3,4,5};
//方法1:
//定义数组类型
typedef int(MY_ARR)[5];
//建立引用
MY_ARR & arr2 = arr;
//方法2:
//直接定义引用
int (&arr3)[5] = arr;
//方法3:
typedef int (&MY_ARR1)[5];
MY_ARR1 arr4 = arr
指针的引用(难点):
c语言中如果想改变一个指针的指向而不是它所指向的内容,函数声明可能这样:
void fun(int**);
,这样很麻烦,传参还要传指针的地址
char * p = "hello!";
char* &p1 = p;
cout<<p1<<endl;
struct Teacher{
int mAge;
};
//指针间接修改teacher的年龄
void AllocateAndInitByPointer(Teacher** teacher){
*teacher = (Teacher*)malloc(sizeof(Teacher));
(*teacher)->mAge = 200;
}
//引用修改teacher年龄
void AllocateAndInitByReference(Teacher*& teacher){
teacher->mAge = 300;
}
void test(){
//创建Teacher
Teacher* teacher = NULL;
//指针间接赋值
AllocateAndInitByPointer(&teacher);
cout << "AllocateAndInitByPointer:" << teacher->mAge << endl;
//引用赋值,将teacher本身传到ChangeAgeByReference函数中
AllocateAndInitByReference(teacher);
cout << "AllocateAndInitByReference:" << teacher->mAge << endl;
free(teacher);
}
常量引用:
格式:const type &ref = val;
注意:
字面量不能赋值给引用,但是能够赋值给常量引用
const int &ref3 = 10; //编译器会把上面代码变为:int tmp = 10;const int &ref3 = tmp;
const
修饰的引用,不能修改
内联函数:出现的原因是想解决#define的一些缺陷
格式:在函数前加上inline
,即向编译器申请成为内联函数,因此内联仅仅只是给编译器一个建议。[最终决定权不在程序员,由编译器决定,因此不可控]
没有加
inline
的函数也有可能成为内联函数
什么时候不会成为内联函数:
- 有过多的条件判断语句
- 存在循环语句
- 函数体过大
- 对函数进行取址操作
内联函数的好处:
- 有宏函数的效率,但规避了其缺点
- 类内部定义的成员函数默认加上
inline
函数的默认参数:[增加函数的灵活性]
注意:
函数的默认参数从左向右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数。
如果函数声明和函数定义分开写,函数声明和函数定义不能同时设置默认参数。
void func(int a,int b = 10); void func(int a,int b){ }
函数的占位参数:[应用于运算符重载时区分前++和后++]
void func(int a,int){
}
func(10,20);
//占位参数也可以有默认值
void func2(int a,int = 1){
}
func2(10);
函数重载:允许函数名相同
实现条件:
- 同一个作用域
参数个数
不同参数类型
不同参数顺序
不同
函数重载没有 返回值 的相关要求。为什么呢?
当编译器能从上下文中确定唯一的函数的时,如
int ret = func()
,这个当然是没有问题的。然而,我们在编写程序过程中可以忽略他的返回值。那么这个时候,假如一个函数为void func(int x);
另一个为int func(int x);
当我们直接调用func(10)
,这个时候编译器就不确定调用那个函数。所以在c++中禁止使用返回值作为重载的条件。
调用重载函数时的注意事项:
严格的类型匹配,若类型不匹配则尝试转换,转换成功就调用,失败就报错。
函数重载和函数默认参数一起使用时需要注意二义性问题出现
void func(int a,int b= 10){ } void func(int a){ } a = 10; func(a);//出现二义性
函数重载的原理:汇编过程取别名
编译器为了实现函数重载,也是默认为我们做了一些幕后的工作,编译器用不同的参数类型来修饰不同的函数名,比如
void func();
编译器可能会将函数名修饰成_func
,当编译器碰到void func(int x)
,编译器可能将函数名修饰为_func_int
,当编译器碰到void func(int x,char c)
,编译器可能会将函数名修饰为_func_int_char
类class
struct
和class
的区别?
class
默认访问权限为private
,struct
默认访问权限为public
.
访问权限:private、protected、public
- 类内没有访问权限限制,均都可访问
- 公有
public
可以在对象外部访问,私有private
和保护protected
可以在对象外部访问- 子类的类内可以访问父类的保护权限
protected
成员
类的静态成员变量static
注意点:
静态成员变量必须在类中声明,在类外定义
AAAA::static_a = 100;//类外定义
静态数据成员不属于某个对象,在为对象分配空间中不包括静态成员所占空间[即静态成员变量属于类,不属于对象,所有对象共享]
静态数据成员可以通过类名或者对象名来访问
生命周期为整个程序,作用域在类内
类的静态成员函数:
注意点:
- 静态成员函数只能访问静态成员变量
- 静态成员函数也有访问权限
- 普通成员函数可访问静态成员变量、也可以访问非静态成员变量
定义
静态const
数据成员时,最好在类内部初始化
为什么要出现静态成员变量?
节省空间,属于类,所有对象共享。
静态成员应用的一个实例: 单例模式----一个类只能实例化一个对象
单例模式常常用于只需要一个对象的场景中
思路:
-把无参构造函数和拷贝构造函数私有化
-定义一个类内的静态成员指针,在类外初始化时,new一个对象
-把指针的权限设置为私有,然后提供一个静态成员函数让外面获取这个指针
例子:
用单例模式,模拟公司员工使用打印机场景,打印机可以打印员工要输出的内容,并且可以累积打印机使用次数。
#include <iostream>
#include <string>
using namespace std;
//打印机类
class Printer {
public:
void printInfo(string info) {
cout << "当前是第" << printTimes << "次打印...." << endl;
cout << "打印内容如为: " << info << endl;
printTimes++;
}
//静态成员函数才能访问静态变量
static Printer* getObject() {
return pter;
}
private:
//私有化,防止用户进行普通构造和拷贝构造
Printer() {
printTimes = 0;
}
Printer(const Printer& other) {
}
private:
//指向当前类的指针,静态成员变量
static Printer* pter;
int printTimes;
};
//在类外进行一次初始化
//为什么这里能进行一个构造[初始化]呢?
//因为有Printer::作用域,编译器把它当作了在类内,而在类内没有访问权限限制
Printer* Printer::pter = new Printer;
int main()
{
Printer* pA = Printer::getObject();
pA->printInfo("C++真tm有意思!");
pA->printInfo("C++真tm难!");
Printer* pB = Printer::getObject();
pB->printInfo("我觉得C++很简单!");
cout << "pA:" << pA << " pB:" << pB << endl;
system("pause");
return 0;
}
输出内容如下:
当前是第0次打印....
打印内容如为: C++真tm有意思!
当前是第1次打印....
打印内容如为: C++真tm难!
当前是第2次打印....
打印内容如为: 我觉得C++很简单!
pA:010D13B0 pB:010D13B0
可见pA和pB是同一个对象~
构造函数和析构函数:
实例化对象时,内部做了两件事:分配空间和调用构造函数进行初始化;在对象销毁前,编译器调用析构函数[释放该对象申请的堆空间等操作]。
注意:
- 构造函数和析构函数必须是公有的。构造函数私有时,实例不了对象。
- 构造函数可以重载,析构函数不行。
- 构造函数和析构函数没有返回值。
- 编译器会默认提供默认构造函数和默认析构函数
拷贝构造函数:用一个已有的对象去初始化另外一个对象
拷贝构造函数的情况:
对象以值传递的方式传给函数参数
用一个对象初始化另一个对象
函数局部对象以值传递的方式从函数返回
-VS Debug模式返回的对象和局部对象地址不同
-VS Release模式返回的对象和局部对象地址相同
class AAAA {
private:
int a;
public:
AAAA() {
a = 999;
cout << "无参构造函数" << endl;
}
AAAA(int data) {
a = data;
cout << "有参构造函数" << endl;
}
AAAA(const AAAA& s) {
a = s.a;
cout << "拷贝构造函数" << endl;
}
};
//测试函数
void test() {
AAAA a1; //调用无参构造函数
AAAA a2(a1); // 调用拷贝构造函数
AAAA a3 = a1; //调用拷贝构造函数
AAAA(10); //调用有参构造函数,这是一个匿名对象
AAAA a4 = 10; //调用有参构造函数,进行了隐式转换,等价于A s = A(10); 如果不想要优化,则使用 explicit 关键字
//explicit 只能放在构造函数前面,构造函数只有一个参数或其他参数为默认参数时
AAAA a5(AAAA(200)); //调用有参构造函数
AAAA a6 = AAAA(200); //调用有参构造函数
AAAA a7 = AAAA(); //调用无参构造函数
}
注意:
编译器也提供了
默认拷贝构造函数
,进行成员变量的简单拷贝。拷贝构造函数的形参要用引用。因为编译器会把形参的值传递看成一个拷贝构造函数,造成死循环构造函数,而引用只是创建了一个别名。
不能调用拷贝构造函数去初始化匿名对象
AAAA t1; //会报错error C2086:“Teacher t1”: 重定义 AAAA(t1); //此时等价于 AAAA t1;
匿名对象的生命周期在当前行
如果匿名对象有东西接,那么就不是匿名对象
AAAA a6 = AAAA(200);
编译器提供构造函数规则:
- 默认情况下,C++编译器至少为我们写的类增加3个函数
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对类中非静态成员属性简单值拷贝
- 如果用户定义拷贝构造函数,C++不会再提供任何默认构造函数
- 如果用户定义了普通构造(非拷贝),C++不在提供默认无参构造,但是会提供默认拷贝构造
多个对象的构造和析构:
- 如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数,析构函数调用顺序相反;
- 成员对象的构造函数调用和定于顺序一样
- 必须保证成员对象的构造和析构能被调用
初始化列表:
- 如果使用了初始化列表,那么所有的构造函数都要使用初始化列表
- 初始化列表只能使用于构造函数
对象的深、浅拷贝:
默认的拷贝构造函数进行了浅拷贝,简单的赋值操作
浅拷贝问题:调用默认拷贝构造函数后,新对象和旧对象指向同一块空间,进行析构函数时被释放了两次,引发错误。
使用深拷贝解决:
class person{
public:
person(char * Name,int Age){
name = (char *)malloc(sizeof(strlen(Name)+1));
strcpy(name,Name);
age = Age;
}
person(const person & p){
name = (char *)malloc(sizeof(strlen(P.name)+1));
strcpy(name,P.name);
age = P.age;
}
~person(){
if(name != NULL){
free(name);
}
}
private:
char * name;
int age;
}
C++对象模型
- 空类大小为1
- 类的成员函数不占类大小[在公共函数代码区],静态成员不占类大小。普通成员变量占用类的
- 类的成员函数和成员变量时分开存储的。
this
指针:一种隐含指针,指向被调的成员函数所属对象
注意:
- 每个对象都有一个隐藏this指针,但不属于对象(不影响
sizeof(对象)
的结果),是编译器添加的。- 编译器会把this指针传入成员函数内。
- 静态成员函数中不能使用this指针[因为静态成员不属于对象,属于类]
- this指针不能改变[说明this类型是常指针
class const * p
]
C++编译器对普通成员函数的内部处理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajiToNkl-1627189637084)(F:\Typora\Picture\Cpp\2021-07-23_233143.jpg)]
this指针的使用:
- 当形参和成员变量同名时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身,可使用
return *this
常函数与常对象
const
修饰成员函数:在成员函数的后面加上const
,使函数成为常函数
//const修饰成员函数
class Person{
public:
Person(){
this->mAge = 0;
this->mID = 0;
}
//在函数括号后面加上const,修饰成员变量不可修改,除了mutable变量
void Operate() const{
//this->mAge = 200; //mAge不可修改
this->mID = 10; //const Person* const tihs;
}
void ShowPerson(){
cout << "ID:" << mID << " mAge:" << mAge << endl;
}
private:
int mAge;
mutable int mID;//被mutable修饰时可以在常函数中被修改
};
注意:
用
const
修饰的成员函数时,const
修饰this
指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量。this指针类型: Person * const this; 在常成员函数中的this指针类型被改为: const Person * const this;
当成员变量类型符前用
mutable
修饰时例外。
const
修饰对象,使其成为了常对象。
const Person MY;
注意:
- 常对象,不能调用普通成员函数,只能调用
const
的成员函数。- 常对象可访问
const
或非const
数据成员,但是不能修改,除非成员用mutable修饰。
常函数和常对象有什么用呢?
如果当前成员函数不打算修改成员变量,就最好定义为常函数
友元:使得全局函数、成员函数和类可以访问私有成员,即给一个函数、或者某个类拥有特殊权限
特点:
- 有元函数不是类的成员函数,没有this指针
- friend关键字只出现在声明处
- 其他类、类成员函数、全局函数都可声明为友元
- 友元函数可访问对象任意成员属性,包括私有属性
- 一定程度上破坏了类的封装性
class Building;
class MyFriend{
public:
void LookAtBedRoom(Building& building);
void PlayInBedRoom(Building& building);
};
void MyFriend::LookAtBedRoom(Building& building){
cout << "我的朋友参观" << building.mBedroom << endl;
}
void MyFriend::PlayInBedRoom(Building& building){
cout << "我的朋友玩耍在" << building.mBedroom << endl;
}
class Building{
//全局函数做为友元函数
friend void CleanBedRoom(Building& building);
#if 0
//将类的成员函数做为友元函数
friend void MyFriend::LookAtBedRoom(Building& building);
friend void MyFriend::PlayInBedRoom(Building& building);
#else
//将某个类作为友元类
friend class MyFriend;
#endif
public:
Building();
public://公有成员变量
string mSittingRoom;
private://私有成员变量
string mBedroom;
};
//构造函数
Building::Building(){
this->mSittingRoom = "客厅";
this->mBedroom = "卧室";
}
//友元全局函数
void CleanBedRoom(Building& building){
cout << "友元全局函数访问" << building.mBedroom << endl;
}
int main(){
Building building;
MyFriend myfriend;
CleanBedRoom(building);
myfriend.LookAtBedRoom(building);
myfriend.PlayInBedRoom(building);
system("pause");
return EXIT_SUCCESS;
}
注意:
友元关系不能被继承
你爸爸的朋友不一定是你的朋友
友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。
你把他当朋友,但他不一定把你当朋友
友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。
你朋友的朋友不一定是你的朋友
运算符重载:目的是为了简化语法,只是另一种函数调用的方式
注意:
- 运算符重载不能改变本来寓意,不能改变基础类型寓意
- 不能改变运算符优先级,不能改变运算符的参数个数
语法:
定义重载的运算符就像定义函数,只是该函数的名字是
operator@
,这里的@
代表了被重载的运算符。函数的参数中参数个数取决于两个因素。运算符是一元(一个参数)的还是二元(两个参数);
运算符被定义为全局函数(对于一元是一个参数,对于二元是两个参数)还是成员函数(对于一元没有参数,对于二元是一个参数-此时该类的对象用作左耳参数)
除了赋值号
=
外,基类中被重载的操作符都将被派生类继承。
=, [], () 和 ->
操作符只能通过成员函数进行重载
<<
和>>
操作符最好通过友元函数进行重载不要重载
&&
和||
操作符,因为无法实现短路规则
运算符重载过程:
-编译器看到两个对象的运算操作,那么编译器就回去寻找有没有对于的
operator
重载函数-编译器检查参数是否对应
-没有问题的话编译器就会执行该函数
+、-、*、/号运算符重载
以一个复数对象的+、-、*、/运算作为例子
//ComplexNUm.h
#pragma once
#include<iostream>
using namespace std;
class ComplexNum
{
public:
ComplexNum();
ComplexNum(double r, double i);
ComplexNum(const ComplexNum& other);
void Printcomplex();
//三个成员函数重载运算符
ComplexNum operator+(ComplexNum& other) {
ComplexNum tmp(this->real + other.real, this->image + other.image);
return tmp;
}
ComplexNum operator*(ComplexNum& other) {
ComplexNum tmp(this->real * other.real - this->image * other.image, this->real * other.real + this->image * other.image);
return tmp;
}
ComplexNum operator/(ComplexNum& other) {
double mul = other.real * other.real + other.image * other.image;
ComplexNum tmp((this->real * other.real + this->image * other.image) / mul, (this->image * other.real - this->real * other.image) / mul);
return tmp;
}
public:
double real;
double image;
};
//ComplexNUm.cpp
#include "ComplexNUm.h"
ComplexNum::ComplexNum() {
real = 0.0;
image = 0.0;
}
ComplexNum::ComplexNum(double r, double i) {
real = r;
image = i;
}
ComplexNum::ComplexNum(const ComplexNum& other) {
real = other.real;
image = other.image;
}
void ComplexNum::Printcomplex() {
if (image >= 0)
cout << real << "+" << image << "i" << endl;
else
cout << real << "" << image << "i" << endl;
}
//全局重载运算符
ComplexNum operator-(ComplexNum& my, ComplexNum& other) {
ComplexNum tmp(my.real - other.real, my.image - other.image);
return tmp;
}
左移右移运算符重载
<<
注意点:
- 形参和实参是一个对象
ostream
形参和返回值要引用,因为ostream
中把拷贝构造函数私有了- 如果要和
endl
一起使用,那么必须返回ostream
的对象
对与
cout<<endl;
endl
是一个函数,作为参数传入了operator<<(endl)
//重载<<是为了方便打印对象
ostream &operator<<(ostream &out,Person & m){
cout<<"name"<<m.name<<" age:"<<m.age<<endl;
return out;
}
//如果Person类的name、age属性为private,可以将其重载运算符函数定义为友元函数
istream & operator>>(istream &in,Person & m){
cin>>m.name>>m.age;
return in;
}
赋值=运算符的重载
默认的赋值运算符重载函数进行了简单的赋值操作[可能会出现内存泄露和同一块内存被释放两次],如下
因此需要重写赋值运算符重载函数
//返回Student是为了防止 s1 = s2 = s3的错误;
Student & operator=(const Studen &stu){
//因为不能确定this指向的空间能否装下stu内数据,需要先释放,再重新申请
if(this->pName != NULL){
delete[] this->pName;
this->pName = NULL;
}
//重新申请空间
this->pName = new char [strlen(stu.pName) + 1];
strcpy(this->pNmae,stu.pName);
return *this;
}
//上述:为什么要返回引用呢?没有引用则会调用拷贝构造
对于s1 = s2 = s3,如果返回的是值,则会产生新的对象,则赋值运算符本来的意义就错了
关系运算符重载
bool operator==(Student & stu){
return this->id == stu.id;
}
// > < 等关系运算符同理
前++和后++运算符重载 [运用到了占位参数]
//前置++
Person & operator++(){
++this->id;
return *this;
}
//后置++
Person operator++(int ){//占位参数,必须是int
Person tmp (*this);//拷贝构造 ,产生了新对象
this->id++;//修改this
return tmp;//返回的是tmp
}
//后置++不能返回引用,因为tmp为局部对象
//优先前置++,因为效率高,不需要产生新的对象
数组下标重载
int &operator[](int index){
if(this->mSize <= index)
this->mSize++;
return this->arr[index];
}
指针运算符重载
class Smartptr{
public:
Smartptr(){
}
Smartptr(Person * p){
person = p;
}
Person & operator*(){
return *(this->person);
}
Person * operator->(){
return this->person;
}
private:
Person * person;
}
Person * p = new Person();
SmartPtr smp(p);
//假设Person类有printfinfo;方法,则可以直接使用->间接调用
smp->printfinfo();
(*smp).printfinfo();
重载函数调用符号
void operator()(){
cout<<"我其实不是个函数"<<endl;
}
为什么要重载函数调用符号?
方便代码维护:写成全局重载函数,大家都可以调用
作为算法的策略
方便有权限的调用函数
后面内容太多,太多图片需要上传…太麻烦了,需要PDF文档的链接如下自己拿:
链接:https://pan.baidu.com/s/1Wb8G6gB2jVbZhqtNAcO5yA
提取码:enay
如有帮助求点赞,谢谢!