网站建设系统 开源,商城版网站制作,wordpress 主页空白,个人社保缴费凭证一.友元
C中使用关键字friend可以在类外访问所有的成员#xff0c;包括私有成员#xff08;之前提到过封装的核心思想是隐藏内部实现细节#xff0c;通过公共接口控制访问#xff09;#xff0c;所以友元可以突破封装的限制访问数据#xff0c;盲目使用会导致程序稳定性… 一.友元
C中使用关键字friend可以在类外访问所有的成员包括私有成员之前提到过封装的核心思想是隐藏内部实现细节通过公共接口控制访问所以友元可以突破封装的限制访问数据盲目使用会导致程序稳定性降低所以使用友元必须慎重。 友元分类 友元函数 友元类 友元成员函数 1.友元函数
全局函数访问私有成员可以配合运算符重载使用友元函数是一种在类内“声明”类外定义的非成员函数但是没访问类内所有的成员。友元函数可以做到修改私有成员变量 注意 (1)友元函数没有this指针。 (2)友元函数可以在类的私有部分也可以在类的公有部分。 (3)一个函数可以是多个类的友元函数只需要在不同的类汇中声明。 #include iostream
#include stringusing namespace std;class Techer{
private:int age 45;string name zhangsna;
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name(lisi){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout get_age() endl;cout get_name() endl;}int print_age(){return 18;}friend void print_real_age(Techer t); //类内声明友元函数
};void print_real_age(Techer t){ //类外定义友元函数cout 真实年龄 t.age endl;cout 虚假年龄 t.print_age() endl;t.age 30;cout 修改年龄 t.age endl;
}int main (){Techer t1(34,zhangsan);cout t1.print_age() endl;print_real_age(t1);return 0;
}2.友元类
当B是A的友元类时,类B就可以访问类A的所有成员 需要注意的是 (1)友元类不具备交换性A声明B为友元 → B可访问A的私有成员但A不能访问B的私有成员。 (2)友元类不具备传递性A是B的友元B是C的友元 → A不是C的友元。 (3)友元类不具备继承性基类友元不会继承给派生类。 #include iostream
#include stringusing namespace std;class Techer{
private:int age 45;string name zhangsna;
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name(lisi){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout get_age() endl;cout get_name() endl;}int print_age(){return 18;}friend class student;
};class Student{
public:void get_name(Techer t){cout t.get_name() endl;}
};int main (){Techer t1(34,zhangsan);Student s1;s1.get_name(t1);return 0;
}友元成员函数
#include iostream
#include stringusing namespace std;class Techer; //声明类class Student{
public:void print_name(Techer t);
};class Techer{
private:int age 45;string name zhangsna;
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name(lisi){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout get_age() endl;cout get_name() endl;}int print_age(){return 18;}friend void Student::print_name(Techer t); //1.友元声明
};//4.实现友元函数
void Student::print_name(Techer t){cout t.get_name() endl;
}int main (){Techer t1(34,zhangsan);Student s1;s1.print_name(t1);return 0;
}二.函数运算符重载
C中函数是可以重载的运算符也是一种特殊的函数也可以重载这样一来本来只能基本数据类型能做的加减乘除也可以让对象直接加减乘除。
函数的三要素是函数名参数和返回值。
下面就是C中运算符含义所以我们对函数进行重载就可以实现对象之间相加。 可以被重载的运算符了解 算术运算符: 、-、*、人、%、、-- 位操作运算符:、|、、^(位异或)、(左移)、(右移) 逻辑运算符、、 比较运算符、、、《、、 赋值运算符:、、-、*、/、%、、 I、^、《、 其他运算符:范、0、-、、new、delete、new[、delete[ 不被重载的运算符 成员运算符、指针运算符“*”、三目运算符?“、sizeof、作用域 1.使用友元函数运算符重载
函数名
参数const Integer i1和const Integer i2
返回值Inteder friend Integer operator (const Integer i1,const Integer i2);
#include iostream
#include stringusing namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value a;}friend Integer operator (const Integer i1,const Integer i2);friend Integer operator (Integer i);friend Integer operator (Integer i,int);
};Integer operator (const Integer i1,const Integer i2){return i1.value i2.value; //返回两个int类型这个时候编译器会自动帮你创建一个Integer类型的副本类似于return Integer(i1.value i2.value);
}
Integer operator (Integer i){return i.value;
}
Integer operator (Integer i,int){return i.value;
}int main (){Integer i1(3);Integer i2(4);Integer i3 i1 i2;cout i3.get_value() endl;i3;cout (i3).get_value() endl;cout i3.get_value() endl;return 0;
}2.使用成员函数运算符重载 简单三步实现投机取巧的方式 (1).把友元函数实现的代码的friend去掉 (2).再把所有传入的第一个参数去掉函数内使用this指针替换不加也可以编译器自动识别 (3).在函数名前加上作用域限定符Integer:: 正常直接写就是写成员函数的步骤。
#include iostream
#include stringusing namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value a;}Integer operator (const Integer i);Integer operator ();Integer operator (int);
};Integer Integer::operator (const Integer i){return value i.value;
}
Integer Integer::operator (){return value;
}
Integer Integer::operator (int){return value;
}int main (){Integer i1(3);Integer i2(4);Integer i3 i1 i2;cout i3.get_value() endl;i3;cout (i3).get_value() endl;cout i3.get_value() endl;return 0;
}3.特殊运算符重载
3.1复制运算符重载 如果程序员不手写赋值运算符重载函数则编译器会自动为每个类增加一个赋值运算符重载函数。 在 C 中赋值运算符operator必须被重载为类的成员函数而不能作为友元函数或全局函数。这一设计决策源于 C 语言的核心特性 1、根本原因语言规范要求 C 标准ISO/IEC 14882明确规定赋值运算符必须被声明为类的非静态成员函数。这是语言规范层面的硬性规定违反此规则将导致编译错误。 2、技术原因this 指针机制 1. 成员函数的隐式 this 指针 成员函数自动获得隐式 this 指针指向调用对象 赋值操作需要修改左操作数的状态this 提供直接访问 2. 友元函数缺少 this 指针 友元函数没有隐式 this 指针 必须显式声明两个参数左操作数和右操作数 违反赋值运算符的二元操作符语法形式 #include iostream
#include stringusing namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this-str str;}String operator (const String a){ //系统默认自带的this-str a.str;return *this;}
};int main (){String s1(hello );String s2(world);s1 s2;cout s1.get_str() endl;return 0;
}3.2类型转换运算符重载
如果我们想把string类型转换为成员变量如果正好你的成员变量只有一个string类型的成员变量这个时候编译器会自动帮你赋值优化String s1 name;就不会报错但是你要是想把s1对象赋值给string类型的name这个时候编译器就无法识别需要使用成员函数进行重载。
可以把注释的部分去掉错误就没了注视部分就是类型转换重载。
#include iostream
#include stringusing namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this-str str;}/*operator string(){return str;}*/
};int main (){String s1(hello );String s2(world);s1 s2;string name s1;cout name endl;cout s1.get_str() endl;return 0;
}4.注意
1.重载的运算符只能对C语言中已有的运算符进行操作,不能创建新的运算符;
2.运算符重载也是函数重载;
3.运算符不能改变运算符的优先级*的优先级比大不能改变和结合性a*b就是a*b不能ab*运算,也不能改变操作数和语法结构
4.运算符重载函数不支持默认参数即运算符的操作数数量固定如二元运算符需要两个操作数
5.运算符重载函数的操作数中一定包含自定义类型运算符重载函数的操作数中必须至少有一个是用户定义类型
三.string字符串常用手册
C函数手册:
通过网盘分享的文件C函数手册 (LibraryFunctions).chm 链接: https://pan.baidu.com/s/17gE3aR6VQhQQ10tBZNFfHg 提取码: 3589
#include iostream
#include string.husing namespace std;int main()
{string s1 ABC;// 隐式调用了下面的参数为const char*string s2(ABC);string s3 s2; // 拷贝构造函数cout s3 endl; // ABC// 参数1const char*// 参数2保留前几个字符string s4(ABCDE,2);cout s4 endl; // ABs1 ABCDE;// 参数1string// 参数2不保留前几个字符string s5(s1,2);cout s5 endl; // CDE// 参数1字符数量// 参数2字符内容string s6(3,Z);cout s6 endl; // ZZZswap(s5,s6);cout s5 s6 endl; // ZZZ CDE// 向后追加字符串cout s1.append(...).append(s5) endl;// 向后追加单字符s6.push_back(O);cout s6 endl; // CDEO// 参数1插入的位置// 参数2插入的内容s6.insert(1,222);cout s6 endl;// 参数1删除的起始位置// 参数2删除的字符数s6.erase(1,3);cout s6 endl;// 参数1替换的起始位置// 参数2替换的字符数// 参数3替换的字符s6.replace(0,3,xxxxxxx);cout s6 endl;s6.clear(); // 清空// 判断是否为空cout s6.empty() endl; // 1char c[20];s6 ABCDEFG;// 参数1拷贝的目标// 参数2拷贝的字符数// 参数3拷贝的起始点s6.copy(c,2,3);cout c endl;char c2[20];s6 ABCDEFG;// c_str返回的char*指向一个内部数组相对不可控cout s6.c_str() endl;// 因此需要拷贝出来strcpy(c2,s6.c_str());cout c2 endl;return 0;
}练完后会不会有个疑问为什么string有这么多操作之前说过他不是基本数据类型因为它就是C中定义好的类。