友元函数及运算符
友元函数
- friend关键字
- 类中的private关键字修饰的成员都不能在类之中进行访问。
- 作用: 在类之外达到可以访问私有成员的目的。
形式:
1、普通函数
2、成员函数
3、友元类
//普通函数写法
#include<bits/stdc++.h>
using namespace std;
class Point {
public:
Point(int ix=0,int iy=0)
:_ix(ix)
,_iy(iy)
{
}
void print() const{
cout<<"("<<_ix
<<","<<_iy<<")"<<endl;
}
//友元之普通函数
friend double getDistance(const Point &lhs,const Point &rhs);
private:
int _ix;
int _iy;
};
double getDistance(const Point &lhs,const Point &rhs){
return sqrt((lhs._ix-rhs._ix)*(lhs._ix-rhs._ix)+
(lhs._ix-rhs._ix)*(lhs._ix-rhs._ix));
}
void test0(){
Point pt1(1,2),pt2(3,4);
cout<<"pt1:";
pt1.print();
cout<<"pt2:";
pt2.print();
cout<<"the distance:"<<getDistance(pt1,pt2)<<endl;
}
int main(){
test0();
return 0;
}
//成员函数
#include <bits/stdc++.h>
using namespace std;
class Point;//类的前向声明
class Line
{
public:
//在函数声明中,是不需要知道Point的具体内容
//此时可以给出该类的前向声明形式
double getDistance(const Point &lhs, const Point &rhs);
};
class Point
{
public:
Point(int ix = 0, int iy = 0)
: _ix(ix), _iy(iy)
{
}
void print() const
{
cout << "(" << _ix
<< "," << _iy << ")" << endl;
}
//2、友元之成员函数
friend double Line::getDistance(const Point &lhs, const Point &rhs);
private:
int _ix;
int _iy;
};
double Line::getDistance(const Point &lhs, const Point &rhs)
{
return sqrt((lhs._ix - rhs._ix) * (lhs._ix - rhs._ix) +
(lhs._ix - rhs._ix) * (lhs._ix - rhs._ix));
}
void test0()
{
Point pt1(1, 2), pt2(3, 4);
cout << "pt1:";
pt1.print();
cout << "pt2:";
pt2.print();
Line line;
cout << "the distance:" << line.getDistance(pt1, pt2) << endl;
}
int main()
{
test0();
return 0;
}
#include <bits/stdc++.h>
using namespace std;
class Point;//类的前向声明
class Line
{
public:
//在函数声明中,是不需要知道Point的具体内容
//此时可以给出该类的前向声明形式
double getDistance(const Point &lhs, const Point &rhs);
void setPoint(Point &pt,int x,int y);
};
class Point
{
public:
//友元之友元类
friend class Line;
Point(int ix = 0, int iy = 0)
: _ix(ix), _iy(iy)
{
}
void print() const
{
cout << "(" << _ix
<< "," << _iy << ")" << endl;
}
private:
int _ix;
int _iy;
};
double Line::getDistance(const Point &lhs, const Point &rhs)
{
return sqrt((lhs._ix - rhs._ix) * (lhs._ix - rhs._ix) +
(lhs._ix - rhs._ix) * (lhs._ix - rhs._ix));
}
void Line::setPoint(Point &pt,int x,int y){
pt._ix=x;
pt._iy=y;
}
void test0()
{
Point pt1(1, 2), pt2(3, 4);
cout << "pt1:";
pt1.print();
cout << "pt2:";
pt2.print();
Line line;
line.setPoint(pt2,5,6);
cout << "the distance:" << line.getDistance(pt1, pt2) << endl;
}
int main()
{
test0();
return 0;
}
友元是否破坏了类的封装性
-
确实破坏了
-
友元做了一些限制:
1、友元不能被继承
2、友元是单向的,不具备传递性
3、友元不具备传递性
比如Line是Point的友元,但是Point并未为line单独声明,因此无法访问Line中的
运算符重载
希望自定义类型在使用时与内置类型的数据操作在形式上保持一致
规则:
1、运算符重载的参数类型只能是自定义类类型和枚举类型。
//内置类型的运算符无法重载
int operator+(int x,int y){
return x-y;
}
2、重载之后,运算符的优先级和结合性还是固定的
3、&& | | 重载之后,就不再具备短路求值特性。
也就是左边的表达式为假,右边的就不需要进行运算了
4、有几个运算符不能重载的:
sizeof //在编译期就已经得到值了,比较早
. //无法重载
?:
.* //成员指针访问运算符
::
5、不能臆造一个并不存在的运算符
形式:
- 普通函数
//参数形式都为const,因为执行之后参数是不修改的,保持不变的
Complex operator +(const Complex &lhs,const Complex &rhs){
return Complex(lhs.getReal()+rhs.getReal(),lhs.getImage()+rhs.getImage());
}
//同时,普通函数不使用友元的话,需要拿get函数支撑
- 成员函数
- 友元函数
特殊运算符重载
复合赋值运算符
- 建议使用成员函数的形式进行重载
Complex &operator+=(const Complex &rhs){
this->_dreal+= this->_dreal;
this->_dimage+=rhs._dimage;
return *this;
}//记得上面的引用,不然就会调用拷贝构造函数
自增自减运算符
- 前置形式与后置形式是有差异;后置形式的参数列表会多一个int,与前置形式进行区分,不需要传参,同时
前置形式的效率更高
下标访问运算符
- vector、map内部也重载了下标访问运算符
#include<bits/stdc++.h>
using namespace std;
class CharArray
{
public:
CharArray(const char *pdata)
:_capacity(strlen(pdata)+1)
,_pdata(new char [_capacity]())
{
strcpy(_pdata,pdata);
}
int size() const{return _capacity-1;}
char &operator[](int idx){
cout<<"char &operator[]"<<endl;
if(idx>=0&&idx<=size()){
return _pdata[idx];
}
else {
static char nullchar='\0';
return nullchar;
}
}//如果返回char,会自动进行复制
~CharArray(){
if(_pdata){
delete[]_pdata;
}
}
private:
size_t _capacity;
char *_pdata;
};
void test0(){
CharArray ca("hellowuhan");
for(int idx=0;idx<ca.size();idx++){
cout<<ca[idx]<<endl;
}
cout<<endl;
}
int main(){
test0();
return 0;
}
成员访问运算符
实现String类的其它运算符的重载
class String
{
public:
String();
String(const char *);
String(const String &);
~String();
String &operator=(const String &);
String &operator=(const char *);
String &operator+=(const String &);
String &operator+=(const char *);
char &operator[](std::size_t index);
const char &operator[](std::size_t index) const;
std::size_t size() const;
const char* c_str() const;
friend bool operator==(const String &, const String &);
friend bool operator!=(const String &, const String &);
friend bool operator<(const String &, const String &);
friend bool operator>(const String &, const String &);
friend bool operator<=(const String &, const String &);
friend bool operator>=(const String &, const String &);
friend std::ostream &operator<<(std::ostream &os, const String &s);
friend std::istream &operator>>(std::istream &is, String &s);
private:
char * _pstr;
};
String operator+(const String &, const String &);
String operator+(const String &, const char *);
String operator+(const char *, const String &);
提示:将上面自定义String的所有函数重新实现一下,注意有些函数是可以相互调用的,这个代码不难,但是相对来说比较繁琐,可以写一个测试一个,降低错误率。
#include<bits/stdc++.h>
using namespace std;
class String
{
private:
char *_pstr;
public:
String()
:_pstr(new char[1]())//初始化
{
cout<<"String()"<<endl;
}
String(const char *pstr)
:_pstr(new char[strlen(pstr)+1]()){//重载
cout<<"String(const char *)"<<endl;
strcpy(_pstr,pstr);
}
String(const String &rhs)
:_pstr(new char[strlen(rhs._pstr)+1]()){
cout<<"String(const String &)"<<endl;
strcpy(_pstr,rhs._pstr);
}
~String()//析构
{
cout<<"~String()"<<endl;
if(_pstr){
delete[]_pstr;
_pstr=nullptr;
}
}
String &operator=(const String &rhs)
{
cout << "String &operator=(const String &)" << endl;
if (this != &rhs)
{
delete[] _pstr;
_pstr = nullptr;
_pstr = new char[strlen(rhs._pstr) + 1]();
strcpy(_pstr, rhs._pstr);
}
return *this;
}
String &operator=(const String *pstr){
cout<<"String &operator=(const char*)"<<endl;
String tmp(*pstr);
*this = tmp;
return *this;
}
String &operator+=(const String &rhs){
cout<<"String &operator+=(const String &rhs)"<<endl;
String tmp;
tmp._pstr=new char[strlen(_pstr)+1]();
strcpy(tmp._pstr,_pstr);
delete []_pstr;
_pstr=nullptr;
_pstr=new char[strlen(rhs._pstr)+strlen(tmp._pstr)+1]();
strcpy(_pstr,tmp._pstr);
strcat(_pstr,rhs._pstr);
return *this;
}
String &operator+=(const char *pstr){
cout<<"String &operator+=(const char *pstr)"<<endl;
String tmp(pstr);
*this+=tmp;
return *this;
}
char &operator[](std::size_t index){
if(index<size()){
return _pstr[index];
}else{
static char nullchar='\0';//必须加static
return nullchar;
}
}
const char&operator[](std::size_t index)const{
if(index<size()){
return _pstr[index];
}else{
static char nullchar='\0';//必须加static
return nullchar;
}
}
std::size_t size() const
{
return strlen(_pstr);
}
const char *c_str() const
{
return _pstr;
}
friend bool operator==(const String &, const String &);
friend bool operator!=(const String &, const String &);
friend bool operator<(const String &, const String &);
friend bool operator>(const String &, const String &);
friend bool operator<=(const String &, const String &);
friend bool operator>=(const String &, const String &);
friend std::ostream &operator<<(std::ostream &os, const String &rhs);
friend std::istream &operator>>(std::istream &is, String &rhs);
};
bool operator==(const String &lhs, const String &rhs)
{
return !strcmp(lhs._pstr, rhs._pstr);
}
bool operator!=(const String &lhs, const String &rhs)
{
return strcmp(lhs._pstr, rhs._pstr);
}
bool operator<(const String &lhs, const String &rhs)
{
return strcmp(lhs._pstr, rhs._pstr) < 0;
}
bool operator>(const String &lhs, const String &rhs)
{
return strcmp(lhs._pstr, rhs._pstr) > 0;
}
bool operator<=(const String &lhs, const String &rhs)
{
return strcmp(lhs._pstr, rhs._pstr) <= 0;
}
bool operator>=(const String &lhs, const String &rhs)
{
return strcmp(lhs._pstr, rhs._pstr) >= 0;
}
std::ostream &operator<<(std::ostream &os, const String &rhs){
if(rhs._pstr){
os<<rhs._pstr;
}
return os;
}
std::istream &operator>>(std::istream &is, String &rhs){
if(rhs._pstr){
delete []rhs._pstr;
rhs._pstr=nullptr;
}
vector<char>buff;
char ch;
while((ch=is.get())!='\n'){
buff.push_back(ch);//输出不为回车时一直输入
}
rhs._pstr=new char[buff.size()+1]();
strncpy(rhs._pstr,&buff[0],buff.size());
return is;
}
String operator+(const String &lhs, const String &rhs)
{
cout << "String operator+(const String &, const String &)" << endl;
String tmp(lhs);
tmp += rhs;
return tmp;
}
String operator+(const String &lhs, const char *pstr)
{
cout << "String operator+(const String &, const char *)"<< endl;
String tmp(lhs);
tmp += pstr;
return tmp;
}
String operator+(const char *pstr, const String &rhs)
{
cout << "String operator+(const char*, const String &)" << endl;
String tmp(pstr);
tmp += rhs;
return tmp;
}
void test0(){
String s1;
cin >> s1;
cout << "s1 = " << s1 << endl;
cout << endl << endl;
String s2 = "hello";
cout << "s2 = " << s2 << endl;
cout << endl << "nihao" << endl;
s2 = "wangdao"; //error
cout << "s2 = " << s2 << endl;
cout << endl << endl;
s2 = s2;
cout << "s2 = " << s2 << endl;
cout << endl << endl;
String s3 = "C++";
s3 += " haonan";
cout << "s3 = " << s3 << endl;
}
int main(){
test0();
return 0;
}
//输出
jing@jing:~/code/2022-4-5$ ./2
String()
nohello
s1 = nohello
String(const char *)
s2 = hello
nihao
String(const char *)
String &operator=(const String &)
~String()
s2 = wangdao
String &operator=(const String &)
s2 = wangdao
String(const char *)
String &operator+=(const char *pstr)
String(const char *)
String &operator+=(const String &rhs)
String()
~String()
~String()
s3 = C++ haonan
~String()
~String()
~String()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】