哪个行业对网站建设需求大,WordPress自适应还移动适配吗,微官网 wordpress,建个网站文章目录#x1f4ac; 一.运算符重载基础知识①基本概念②运算符重载的规则③运算符重载形式④运算符重载建议 二.常用运算符重载①左移()和右移()运算符重载1️⃣重载后函数参数是什么#xff1f;2️⃣重载的函数返回类型是什么#xff1f;3️⃣重载为哪种… 文章目录 一.运算符重载基础知识①基本概念②运算符重载的规则③运算符重载形式④运算符重载建议 二.常用运算符重载①左移()和右移()运算符重载1️⃣重载后函数参数是什么2️⃣重载的函数返回类型是什么3️⃣重载为哪种函数4️⃣代码实现 ②赋值()运算符重载知识卡片 ③关系运算符( ! )重载④前置和后置(/- -)重载思考 ⑤类型转换类型转换函数和转换构造函数1️⃣类型转换函数2️⃣转换构造函数 ⑥数组下标([])运算符重载⑦指针运算符(*、 -)重载智能指针类 ⑧函数调用()运算符重载——仿函数 一.运算符重载基础知识
C的一大特性就是重载重载使得程序更加简洁高效。在C中不只函数可以重载运算符也可以重载运算符重载主要是面向对象之间的。
①基本概念
运算符重载就是对已有的运算符重新进行定义赋予其另一种功能以适应不同的数据类型。
//对于基础数据类型运算符可以有很好的效果
int a20,b20;
int cab;
//对于自定义数据类型类创建的对象运算是十分繁琐的
//例如
class Maker
{
public://有参构造函数Maker(int id, int age){this-id id;this-age age;}public:int id;int age;
};
void test()
{Maker m1(1,19);Maker m2(2,20);Maker m3(3,17);m3m1m2;//err
//如果我们想要m1和m2相加赋值给m3我们可以这样写
//m3.idm1.idm2.id;
//m3.agem1.agem2.age;
//这样写太繁琐如果对象内部有很多成员变量而且还是私有怎么办
//C用运算符重载来解决问题
}运算符重载语法 在C中使用operator关键字定义运算符重载。运算符重载语法格式如下 函数的参数列表中参数个数取决于两个因素。 运算符是单目(一个参数)的双目(两个参数) ❤️运算符被定义为全局函数对于单目运算符是一个参数对于双目运算符是两个参数。 ❤️被定义为类的成员函数对于单目运算符没有参数对于双目运算符是一个参数因为类本身为左侧参数this。 这种定义很像一个普通的函数定义只是函数的名字由关键字operator及其紧跟的运算符组成。差别仅此而已。它像任何其他函数一样也是一个函数当编译器遇到适当的模式时就会调用这个函数。 通过案例两个对象相加演示“”运算符的重载
class Maker
{
public:Maker(int id, int age){this-id id;this-age age;}
public:int id;int age;
};
Maker operator(Maker p1,Maker p2)//2.编译器检查参数是否对应第一个参数是加号的左边第二参数是加号的右边
{Maker temp(p1.id p2.id, p1.age p2.age);return temp;
}
void test()
{Maker m1(1, 20);Maker m2(2, 22);Maker m3m1 m2;//1.编译器看到两个对象相加那么编译器会去找有没有叫operator的函数cout id: m3.id age: m3.age endl;//多个对象相加Maker m4 m1 m2 m3;cout id: m4.id age: m4.age endl;
}通过上面案例可以知道重载运算符并没有改变其原来的功能只是增加了针对自定义数据类型的运算功能具有了更广泛的多态特征。
②运算符重载的规则
只能重载C中已有的运算符且不能创建新的运算符。例如一个数的幂运算试图重载“* *”为幂运算符使用2 ** 4表示2^4是不可行的。重载后运算符不能改变优先级和结合性也不能改变操作数和语法结构。运算符重载的目的是针对实际运算数据类型的需要重载要保持原有运算符的语义且要避免没有目的地使用运算符重载。例如运算符“”重载后实现相加的功能而不会重载“”为相减或者其他功能。并非所有C运算符都可以重载可以重载的运算符如下图所示。其他运算符是不可以重载的如“::”、“.”、“.*”、“?:”、sizeof、typeid等。
③运算符重载形式
运算符重载一般有三种形式
重载为普通全局函数不推荐因为重载运算符为普通函数只能访问类的公有成员重载为类的成员函数将重载后的全局函数声明为类的友元函数
④运算符重载建议
✅下面的运算符只能通过类的成员函数进行重载。 :赋值运算符 []:下标运算符 () :函数调用运算符 -:通过指针访问类成员的运算符。 ✅ 和 操作符最好通过类的友元函数进行重载✅不要重载 和 || 操作符因为无法实现短路规则
//短路规则
abc只要a为假整个式子就是假b往后就短路了不需要看
a|b|c只要a为真整个式子就是真b往后就短路了不需要看常规建议 拓展
二.常用运算符重载
①左移()和右移()运算符重载 C输入输出标准库提供了“”和“”运算符执行输入、输出操作但标准库只定义了基本数据类型的输入、输出操作若要直接对类对象进行输入、输出则需要在类中重载这两个运算符。 与其他运算符不同的是输入、输出运算符只能重载成类的友元函数。“”和“”运算符重载的格式如下 解释
1️⃣重载后函数参数是什么
①和是双目运算符重载时函数需要两个参数那么参数的类型是什么要打印的对象类型显而易见但cout和cin这两个对象的类型是什么呢 cout 是 ostream 类的对象。cin是istream类的对象。ostream 、istream类、 cout 和cin都是在头文件 iostream 中声明的。 ⚠️注意重载的函数的参数都需要用引用cout是ostream类的对象cin是istream类的对象ostream类和istream中的拷贝构造函数是私有的无法调用如果不加引用传参时会调用ostream类和istream类中的拷贝构造编译会出现冲突。 2️⃣重载的函数返回类型是什么
以cout为例cin同理重载的函数返回类型可以是void但有缺点一次只能打印一个对象不能连续打印。
coutm1;✔️
coutm1m2m3;✖️等价于voidm2m3
coutm1endl;✖️解决方法就是返回对象为ostream 要加引用()不加引用就调用ostream的拷贝构造函数但ostream类的拷贝构造函数是私有的。
coutm1m2m3;等价于coutm2m3coutm3;3️⃣重载为哪种函数 考虑到cout对象在运算符左边, 如果使用类的成员函数重载的话, 需要在ostream类中重载函数因为ostream是标准库定义的类我们不能更改库中代码在左边不符合要求。 普通函数不能访问类的私有变量直接pass掉。 所以我们选择将重载后的全局函数声明为类的友元函数。 4️⃣代码实现
class Maker
{//声明重载运算符的函数friend ostream operator(ostream out,Maker m1);friend istream operator(istream in,Maker m1);
public:int id;string Name;Maker(int a,int b,int c,string name){this-ida;this-ageb;this-moneyc;this-Namename;}
private:int age;int money;
};
ostream operator(ostream out,Maker m1)
{coutm1.id|m1.age|m1.money|m1.Nameendl;return out;
}
istream operator(istream in,Maker m1)
{inm1.idm1.agem1.moneym1.Name;return in;
}
void test()
{Maker m1(100,18,5999,强风吹拂);Maker m2(100,18,7999,强风吹拂king);coutm1m2;cout请重新为m1和m2对象输入数据endl;cinm1m2;coutm1m2;cout1000100.3142endl;//重载后基础类型照样可以输入输出//因为左移和右移运算符基础类型本没有输入输出的能力//之所以有是因为左移和右移运算符输入输出基本数据在类内已经全部重载一遍了
}②赋值()运算符重载
赋值符常常初学者的混淆。这是毫无疑问的因为’’在编程中是最基本的运算符可以进行赋值操作也能引起拷贝构造函数的调用。
知识卡片 1.编译器默认给类提供了一个默认的赋值运算符重载函数默认的赋值运算符重载函数对成员变量进行了简单的赋值操作。 例如
class Maker
{
public:Maker(){id 0;age 0;}Maker(int id, int age){this-id id;this-age age;}
public:int id;int age;
};
void test()
{Maker m1(10, 20);Maker m2;m2 m1;//赋值操作//默认的赋值运算符重载函数进行了简单的赋值操作cout m2.id m2.age endl;
}2.区分赋值操作和拷贝构造函数因为’’在编程中是最基本的运算符可以进行赋值操作也能引起拷贝构造函数的调用。 区分的关键在于看对象有没有创建。 例如
class Student
{
public:Student(int id, int age){this-ID id;this-Age age;}void Printf(){cout this-ID this-Age endl;}
private:int ID;int Age;
};
void test()
{Student s1(10, 20);//调用拷贝构造Student s2 s1; s1.Printf();s2.Printf();//如果一个对象还没有被创建则必须初始化也就是调用构造函数//上述例子由于s2还没有初始化所以会调用构造函数//由于s2是从已有的s1来创建的所以只有一个选择//就是调用拷贝构造函数Student s3(101, 100);//这是赋值操作s3 s1;s3.Printf();//由于s3已经创建不需要再调用构造函数这时候调用的是重载的赋值运算符
}3.当类的成员变量有指针时有可能会出现两个问题 一是在创建对象调用拷贝构造函数时会出现浅拷贝问题即一个对象的成员变量指针被拷贝给另一个对象的成员变量然后两个对象的成员变量指针指向同一份空间在析构函数调用时就会出现同一块空间释放2次。 解决方法深拷贝。 二是在赋值时两个对象都已被创建此时赋值会导致一个对象的成员变量(指针)会被覆盖导致内存泄露。 解决方法重载运算符。 重载运算符解决上述的第二个问题
class Student
{
public:Student(const char *name){pName new char[strlen(name) 1];strcpy(pName, name);}//防止浅拷贝Student(const Student stu){pName new char[strlen(stu.pName) 1];strcpy(pName, stu.pName);}//重写赋值运算符重载函数Student operator(const Student stu){//1.不能确定this-pName指向的空间是否能装下stu中的数据所以先释放this-pName指向的空间if (this-pName ! NULL){delete[] this-pName;this-pName NULL;}//2.申请堆区空间大小由stu决定this-pName new char[strlen(stu.pName) 1];//3.拷贝数据strcpy(this-pName, stu.pName);//4.返回对象本身return *this;} ~Student(){if (pName ! NULL){delete[] pName;pName NULL;}}void printStudent(){cout Name: pName endl;}
public:char *pName;
};void test()
{Student s1(强风吹拂);Student s2(强风吹拂king);s1.printStudent();s2.printStudent();s1 s2;//赋值操作s1.printStudent();s2.printStudent();
}4.为什么operator返回一个reference to *this ? ①为了实现连续赋值赋值操作符必须返回一个引用指向操作符的左侧实参。这是你为class实现赋值操作符必须遵循的协议。这个协议不仅适用于标准的赋值形式也适用于、-、*等等。 ②如果不加引用对象以值的形式返回会在返回处调用拷贝构造函数产生一个新对象。 例如
void test()
{Student s1(a);Student s2(b);Student s3(c);s1 s2 s3;//s3赋值s2,s2赋值给s1//判断s3赋值给s2返回的是不是s2这个对象。cout (s2 s3) endl;cout s2 endl;
}一方面如果operator返回类型不带引用那么在返回的过程中表达式会调用拷贝构造函数产生一个新的对象就不是s2这个对象了。另外一个方面s1s2s3,赋值运算符本来的寓意是s3赋值s2,s2赋值给s1也就是说s2s3这个表达式要返回s2这个对象所以要返回引用。此处放对比图
③关系运算符( ! )重载
关系运算符如“”或“”也可以重载关系运算符的重载函数返回值类型一般定义为bool类型即返回true或false。关系运算符常用于条件判断中重载关系运算符保留了关系运算符的原有含义。 案例演示关系运算符重载
class Student
{
private:string _id;double _score;
public:Student(string id, double score) : _id(id), _score(score){}void dis(){cout 学号 _id 成绩 _score endl;}
//重载关系运算符friend bool operator(const Student st1, const Student st2);friend bool operator!(const Student st1, const Student st2);friend bool operator(const Student st1, const Student st2);friend bool operator(const Student st1, const Student st2);
};
bool operator(const Student st1, const Student st2)
{return st1._score st2._score;//重载“”运算符
}
bool operator!(const Student st1, const Student st2)
{return !(st1._score st2._score);//重载“!”运算符
}
bool operator(const Student st1, const Student st2)
{return st1._score st2._score;//重载“”运算符
}
bool operator(const Student st1, const Student st2)
{return st1._scorest2._score;//重载“”运算符
}
void test()
{Student st1(22031202000, 101), st2(22031202001, 148);cout 比较两名学生的成绩 endl;if (st1st2)st1.dis();else if (st1st2)st2.dis();elsecout 两名学生成绩相同 endl;
}关系运算符重载有以下几点使用技巧
通常关系运算符都要成对地重载例如重载了“”运算符就要重载“”运算符反之亦然。通常情况下“”运算符具有传递性例如a bb c则a c成立。可以把一个运算符的工作委托给另一个运算符通过重载后的结果进行判断。例如本例中重载“!”运算符是在重载“”运算符的基础上实现的。
④前置和后置(/- -)重载
重载的和- -运算符有点让人不知所措因为前置和后置的运算符一样都是或- -重载后的函数名都是operator- -不便于区分所以C给我们提供了解决方法——占位参数。 即允许写一个增加了无用 int 类型形参的版本编译器处理或–前置的表达式时调用参数个数正常的重载函数处理后置表达式时调用多出一个参数的重载函数。 重载形式
例如
class Maker
{friend ostream operator(ostream out, Maker m);
public:Maker(int a){this-a a;}//重载前置加加重载后的函数参数个数正常0个Maker operator(){//返回类型是你自定义的类型因为有m情况存在this-a;//先完成递增操作return *this;//再返回当前对象}//重载后置加加,重载后的函数参数比正常情况多一个占位参数intMaker operator(int)//占位参数必须是int{//后置加加先返回在加加//但一旦先返回加加就操作不了所以我们采取一个临时对象来延迟返回操作。//先保存旧值然后加加最后返回旧值Maker tmp(*this);//1.*this里面的值a是等于2this-a;//这个对象的a等3return tmp;}
private:int a;
};ostream operator(ostream out, Maker m)
{out m.a endl;return out;
}
void test()
{Maker m1(1);cout m1 endl;//1cout m1 endl;//2//(m1);cout m1 endl;//2 这里返回的拷贝的tmp对象cout m1 endl;//3 这里打印的是this-a的对象//同等条件下优先使用前置加加不需要产生新的对象和调用拷贝构造
}对比前置和后置运算符的重载可以发现后置运算符的执行效率比前置的低。因为后置方式的重载函数中要多生成一个局部对象 tmp而对象的生成会引发构造函数调用需要耗费时间。同理后置–运算符的执行效率也比前置的低。 思考 为什么前置运算符的返回值类型是Maker 而后置运算符的返回值类型是MakerMaker是你自定义的数据类型 原因有二个方面
①是因为运算符重载最好保持原运算符的用法。C 固有的前置运算符的返回值本来就是操作数的引用而后置运算符的返回值则是操作数值修改前的复制品。②后置或- -返回的是局部对象默认情况下局部对象的声明周期局限于所在函数的每次执行期间只有当函数被调用的时候才存在当函数执行完毕时会立即释放分配给局部对象的存储空间。此时对局部对象的引用就会指向不确定的内存。
⑤类型转换类型转换函数和转换构造函数
基本数据类型的数据可以通过强制类型转换操作符将数据转换成需要的类型例如static_cast(3.14)这个表达式是将实型数据3.14转换成整型数据。对于自定义的类C提供了类型转换函数来实现自定义类与基本数据类型之间的转换。
1️⃣类型转换函数
对于自定义的类C提供了类型转换函数用来将类对象转换为基本数据类型。 类型转换函数也称为类型转换运算符重载函数定义格式如下所示 类型转换函数以operator关键字开头这一点和运算符重载规律一致。从类型转换函数格式可以看出在重载的数据类型名前不能指定返回值类型返回值的类型由重载的数据类型名确定且函数没有参数。由于类型转换函数的主体是本类的对象因此只能将类型转换函数重载为类的成员函数。 ✅示例
class king
{
public:king(string id,const char*name){this-IDid;Name new char[strlen(name) 1];strcpy(Name, name);}void Show(){coutID:ID,Name:Nameendl;}
operator char*()//类型转换运算符重载
{//如果要将对象转换为char*指针
//就直接将对象转换为自己的成员char*类型的Namereturn Name;
}
private:string ID;char *Name;
};
void test()
{king k1(2203120000,强风吹拂king);k1.Show();char *PKk1;//调用类型转换函数coutPKendl;//通过调用重载的char*类型转换函数将对象s1成功转换为了char*类型
}将对象k1成功转换为char*类型
2️⃣转换构造函数
转换构造函数指的是构造函数只有一个参数且参数不是本类的const引用。用转换构造函数不仅可以将一个标准类型数据转换为类对象也可以将另一个类的对象转换为转换构造函数所在的类对象。转换构造函数的语法格式如下所示 案例演示转换构造函数 三维坐标类转换为二维坐标类。
class Solid//三维坐标类
{friend class Point;//由于需要在Point类中访问Solid的成员变量//因此将Solid类声明为Point类的友元类。
public:Solid(int x,int y,int z) :x(x), y(y),z(z){}void Show(){cout三维坐标(x,y,z)endl;}
private:int x,y,z;
};
class Point//二维点类
{
public:Point(int x, int y) :x(x), y(y){}Point(const Solid another)//定义转换构造函数{this-xanother.x;this-yanother.y;}void Show(){cout二维坐标(x,y)endl;}
private:int x,y;
};
void test()
{Point p1(1,1);p1.Show();Solid s1(2,2,2);s1.Show();cout三维转换二维坐标endl;p1s1;p1.Show();
}⑥数组下标([])运算符重载
在程序设计中通常使用下标运算符“[]”访问数组或容器中的元素。为了在类中方便地使用“[]”运算符可以在类中重载运算符“[]”。重载“[]”运算符有两个目的
“对象[下标]”的形式类似于“数组[下标]”更加符合用户的编写习惯。可以对下标进行越界检查。
重载下标运算符“[]”的语法格式如下所示 上述格式中“[]”运算符重载函数有且只有一个整型参数表示下标值。重载下标运算符时一般把返回值指定为一个引用因为数组下标既要做到读数据也要做到写数据所以要能当左右值。 ✅案例演示
class MyArray
{
public:MyArray();//无参构造函数MyArray(const MyArray arr);//拷贝构造函数MyArray(int capacity, int val 0);//有参构造参数如果不指名初始值默认为val0。~MyArray();//析构函数//重写赋值运算符重载函数MyArrayoperator(const MyArray m);//重写[]运算符要能当左右值左值可以放数据右值可以读数据int operator[](int index);//打印数据void PrintfMyArray();
private:int *pArray;//指向堆区空间存储数据int mSize;//元素个数int mCapacity;//数组容量
};
//无参构造函数
MyArray::MyArray()
{this-mCapacity 10;this-mSize 0;this-pArray new int[this-mCapacity];for (int i 0; i this-mCapacity; i){this-pArray[i] 0;}
}
//析构函数
MyArray::~MyArray()
{if (this-pArray ! NULL){delete[] this-pArray;this-pArray NULL;}
}
//拷贝构造函数
MyArray::MyArray(const MyArray arr)
{this-mCapacity arr.mCapacity;this-mSize arr.mSize;//1.申请空间this-pArray new int[arr.mCapacity];//2.拷贝数据for (int i 0; i this-mSize; i){this-pArray[i] arr.pArray[i];}
}
//有参构造函数不指定初始值则默认全部初始化为0
MyArray::MyArray(int capacity, int val)
{this-mCapacity capacity;this-mSize capacity;this-pArray new int[capacity];for (int i 0; i this-mSize; i){this-pArray[i] val;}
}//重写赋值运算符重载函数
MyArrayMyArray::operator(const MyArray m)
{//1.释放原来的空间if (this-pArray ! NULL){delete[] this-pArray;this-pArray NULL;}this-mCapacity m.mCapacity;this-mSize m.mSize;//2.申请空间大小由m决定this-pArray new int[m.mCapacity];//3.拷贝数据for (int i 0; i this-mCapacity; i){this-pArray[i] m.pArray[i];}return *this;
}//要能当左右值
int MyArray::operator[](int index)
{ static int x-1;//数组下标检查if(mSizeindex||index0){coutindex越界endl;return x;}else if (this-mSize index){ //当m.Size元素个数等于下标indexthis-mSize;}//当else if执行说明此时要加入新数据此时m.Size先要然后return this-pArray[index];返回的是左值。//上面两个if都不执行说明只读取下标为index的元素然后return this-pArray[index];返回的是右值。return this-pArray[index];
}
void MyArray::PrintfMyArray()
{for(int i0;imSize;i){coutpArray[i] |;//调用[]运算符重载函数输出数组类}
}
void test()
{MyArray arr;//无参构造函数for (int i 0; i 10; i){arr[i] i 10;//调用[]运算符重载函数初始化数组类}arr.PrintfMyArray();cout endl;MyArray arr2(10, 66);//有参构造函数arr2.PrintfMyArray();cout endl;MyArray arr3(arr2);//拷贝构造函数arr3.PrintfMyArray();cout endl;MyArray arr4;arr4 arr;//调用赋值运算符的重载函数arr赋值给arr4arr4.PrintfMyArray();cout endl;arr2[6]10086;//调用[]运算符修改特定下标的值cout arr2[6] |;cout endl;cout arr2[60] |;cout endl;
}⑦指针运算符(*、 -)重载
智能指针类
智能指针(smart pointer)是存储指向动态分配堆对象指针的类用于生存期控制能够确保自动正确的销毁动态分配的对象防止内存泄露。 智能指针的本质是使用引用计数的方式解决悬空指针的问题通过重载“*”和“?”运算符来实现。 为什么有智能指针类 在平时我们写代码的时候用new开辟出来的空间虽然我们知道要进行资源的回收但可能会因为程序执行流的改变导致资源没有归还所导致的内存泄漏的问题智能指针就帮助我们解决这个问题。 在学习引用计数、重载“*”和“?”运算符之前需要理解普通指针在资源访问中导致的指针悬空问题。 例如:
class king
{
public:king(string name) :Name(name){cout king构造函数调用 endl;} ~king(){} void Show() { cout 强风吹拂king的博客 endl;}
private: string Name;
};
void test()
{king *pstr1 new king(感谢支持我的博客);king *pstr2 pstr1;king *pstr3 pstr1;pstr1-Show();delete pstr1;pstr2-Show();
}❗️问题 指针pstr1、pstr2、pstr3共享同一个对象若释放pstr1指向的对象pstr2和pstr3仍然在使用该对象将造成pstr2和pstr3无法访问资源成为悬空指针程序运行时出现异常。 为了解决悬空指针的问题C语言引入了引用计数的概念。引用计数是计算机科学中的一种编程技术用于存储计算机资源的引用、指针或者句柄的数量。当引用计数为零时自动释放资源使用引用计数可以跟踪堆中对象的分配和自动释放堆内存资源。 案例演示
class king
{
public:king(string name) :Name(name){cout king构造函数调用 endl;}~king(){}void Show(){cout 感谢支持强风吹拂king的博客 endl;}
private:string Name;
};
class Count//Count类用于存储指向同一资源的指针数量
{//声明SmartPtr智能指针类为Count类的友元类//因为SmartPtr要访问Count类成员friend class SmartPtr;
public://Count成员pking指向由SmartPtr类传过来king类对象的指针Count(king *pstr1) :pking(pstr1), count(1){cout Count类构造函数 endl;}~Count(){cout Count类析构函数 endl;delete pking;//释放king类指针}
private:king *pking;int count;
};
class SmartPtr//SmartPtr类用于对指向king类对象的指针实现智能管理
{
public://CountNum是成员对象指针指向由king类指针初始化的Count类SmartPtr(king* pstr1) : CountNum(new Count(pstr1)){cout SmartPtr有参构造函数调用 endl;}//拷贝构造函数SmartPtr(const SmartPtr another) :CountNum(another.CountNum){CountNum-count;//只要调用拷贝构造函数就说明多一个指针指向king对象所以countcout Smartptr类拷贝构造函数 endl;}//定义析构函数释放king类对象的资源//当记录指向king类对象指针的数量count为0时释放资源。~SmartPtr(){if (--CountNum-count 0){delete CountNum;//释放指向成员对象Count的指针cout Smartptr类析构函数 endl;}}//通过重载“*”和“-”运算符就可以指针的方式实现king类成员的访问。//-运算符重载返回指向king类对象的指针。king *operator-(){return CountNum-pking;}//*运算符重载返回king类对象。king operator*(){return *CountNum-pking;}int disCount(){return CountNum-count;}
private://成员对象指针Count *CountNum;
};
void test()
{king *pstr1 new king(感谢支持我的博客);SmartPtr pstr2 pstr1;//调用有参构造函数count不所以count的默认值才设为1(*pstr1).Show();SmartPtr pstr3 pstr2;//调用拷贝构造函数countpstr2-Show();cout 使用基类对象的指针数量 pstr2.disCount() endl;
}在使用智能指针申请king类对象存储空间后并没有使用delete释放内存空间。使用智能指针可以避免堆内存泄漏只需申请无须关注内存是否释放。通过重载“*”和“?”运算符可以实现对象中成员的访问。
⑧函数调用()运算符重载——仿函数
1.类里有重载函数调用符号的类实例化的对象也叫仿函数。 2.仿函数的作用
方便代码维护方便有权限的调用函数。作为算法的策略仿函数在STL的算法中使用比较广泛。
class Maker
{
public:Maker(){name 强风吹拂king的博客;}void printMaker(){cout 感谢支持name endl;}//函数调用运算符()重载void operator()(const string str ){cout str endl;}//函数调用运算符()重载void operator()(int v1,int v2){cout v1v2 endl;}
public:string name;
};void test()
{Maker func;func(感谢支持强风吹拂king的博客);//看起来像函数调用其实func是对象func(10, 20);//像调用函数一样调用对象funcfunc.printMaker();
}