当前位置: 首页 > news >正文

day9 cpp:运算符重载

1.友元

什么是友元?

一般来说,类的私有成员只能在类的内部访问,类之外不能访问,但如果将其他类/函数设置为此类的友元,那么友元类/函数就可以在前一个类对的类定义之外访问其私有成员了,用friend关键字声明友元

友元的三种形式:普通函数,成员函数,友元类

普通函数形式

class Point {
public:Point(int x,int y=0):_x(x),_y(y){}void print() const {cout << "(" << this->_x << endl;cout << "(" << this->_y << endl;}//友元的第一种形式//普通 函数声明 为一个类的友元函数//那么在这个函数中可以访问类的私有成员friendfloat distance(const Point& a, const Point& b);
private:int _x;int _y;
};
//建立一个观念
//如果函数的参数为对象
//形参首先想到const引用的方式
float distance(const Point& a, const Point& b) {return sqrt(pow(a._x - b._x, 2) + pow(a._y - b._y, 2));
}

成员函数形式  (不常用)

class Point {
public:Point(int x,int y=0):_x(x),_y(y){}void print() const {cout << "(" << this->_x << endl;cout << "(" << this->_y << endl;}friendfloat distance(const Point& a, const Point& b);
private:int _x;int _y;
};
class line {
public:float distance(const Point& a, const Point& b) {//报错_x,_y是私有成员return sqrt(pow(a._x - b._x, 2) + pow(a._y - b._y, 2));}
};

 之前distance是普通函数,现在distance是类line的成员函数在声明要加上作用域限定

class Point {
public:Point(int x,int y=0):_x(x),_y(y){}void print() const {cout << "(" << this->_x << endl;cout << "(" << this->_y << endl;}friendfloat line::distance(const Point& a, const Point& b);
private:int _x;int _y;
};
class line {
public:float distance(const Point& a, const Point& b) {return sqrt(pow(a._x - b._x, 2) + pow(a._y - b._y, 2));}
};

不仅_x,_y处私有成员变量报错,line::distance声明也报找不到line错误 将line类放在Point类前

class line {
public:float distance(const Point& a, const Point& b) {return sqrt(pow(a._x - b._x, 2) + pow(a._y - b._y, 2));}
};
class Point {
public:Point(int x,int y=0):_x(x),_y(y){}void print() const {cout << "(" << this->_x << endl;cout << "(" << this->_y << endl;}friendfloat line::distance(const Point& a, const Point& b);
private:int _x;int _y;
};

但是distance的实现中又找不到Point对象 ,在类line前进行Point类的前向声明

class Point;
class line {
public:float distance(const Point& a, const Point& b) {return sqrt(pow(a._x - b._x, 2) + pow(a._y - b._y, 2));}
};
class Point {
public:Point(int x,int y=0):_x(x),_y(y){}void print() const {cout << "(" << this->_x << endl;cout << "(" << this->_y << endl;}friendfloat line::distance(const Point& a, const Point& b);
private:int _x;int _y;
};

line类中的distance实现可以创建Point对象,可具体的Point类的成员变量访问不到,

Point类的前向声明:将distance的函数体写在line类中,编译器只知道有一个Point类,但不知道Point类具体有什么成员

t类的前向声明的用处:进行了前向声明的类,可以引用或指针的形式作为函数的参数,只要不涉及对该类对象具体成员的访问,编译器可以通过

 所以将line类中distance实现变为声明,将其实现放到后面,并加上作用域限定

class Point;
class line {
public:float distance(const Point& a, const Point& b);
};
class Point {
public:Point(int x,int y=0):_x(x),_y(y){}void print() const {cout << "(" << this->_x << endl;cout << "(" << this->_y << endl;}//友元的第二种形式//将另一个类成员函数声明为友元函数friendfloat line::distance(const Point& a, const Point& b);
private:int _x;int _y;
};
//这种方式割裂了代码
//使用较少,但是仍要掌握
float line::distance(const Point& a, const Point& b){return sqrt(pow(a._x - b._x, 2) + pow(a._y - b._y, 2));
}

注:缺省参数必须放在声明上(如果分开),因为调用一定在声明之后,可能在实现之前 

友元类形式

如上,假设类line中不只一个distance成员函数,还有其他成员函数,他们都需要访问Point私有成员,如上设置成一个一个友元成员函数很麻烦,可以将line类设置为Point的友元类,相比于成员函数形式更常用

class Point {
public:Point(int x,int y):_x(x),_y(y){}//友元的第三种形式友元类//将line类声明为Point友元类//那么line中所有成员函数都可以访问Point的私有成员friendclass line;
private:int _x;int _y;
};
class line {
public:float distance(const Point& a, const Point& b) {return sqrt(pow(a._x - b._x, 2) + pow(a._y - b._y, 2));}void setX(Point & a,int x) {a._x = x;}
};

 友元的特点

1.友元不受类中访问权限的限制:

可访问私有成员

2.友元破坏了类的封装性

外面的小子都可以访问私有成员了

3.不能滥用友元,友元的使用受到限制

4.友元是单向的

A类是B类的友元,则A类成员函数中可以访问B类私有成员,但B类不是A类的友元

5.友元不具备传递性

A是B的友元类,B是C的友元类,但A不是B的友元类

6.友元不能被继  承

因为友元破坏了类的封装性,为了降低影响,设计层面上友元不能被继承

2.运算符重载

运算符重载的介绍

为了c++中自定义类型与内置类型保持一致

运算符重载的规则与形式(重点)

 运算符重载有以下规则

运算符重载形式

1.采用友元函数的重载形式

2.采用普通函数的重载形式

3.采用成员函数的重载形式 

+运算符重载

实现一个复数类,复数分为实部和虚部,重载+运算符,使其能够处理两个复数之间的加法运算

友元函数形式

class Complex {
public:Complex(int real, int image) :_real(real),_image(image){}void print() {cout << _real << "+" << _image << "i" << endl;}friendComplex operator+(const Complex& lhs, const Complex& rhs);
private:int _real;int _image;
};
//运算符重载的第一种方式--友元函数形式
//定义一个普通函数operator+
//将这个函数声明为Complex类的友元
Complex operator+(const Complex& lhs, const Complex& rhs) {return Complex(lhs._real + rhs._real, lhs._image + rhs.image);
}
void test() {int a = 1, b = 2;//&(a+b) errorint c = a + b;Complex cx1(3, 7);Complex cx2(4, 5);Complex cx3 = cx1 + cx2;//本质Complex cx3=operator+(cx1,cx2); Complex cx3.operator=(operator+(cx1,cx2))cx3.print();//7+12i
}

 Complex cx3=operator+(cx1,cx2)解读:

1.operator+(cx1,cx2)是一个匿名的临时对象

2.cx3=临时对象 赋值

注意:

class T{....};

T t;

T a;

t.operator=(a);//xx()=常量;则xx()一定是左值,int a=xx()中xx()随意

 普通函数形式(几乎不用)

类外访问私有成员,一是用友元函数,二是提供公有的成员函数访问私有成员

class Complex {
public:Complex(int real, int image):_real(real), _image(image){}void print() {cout << _real << "+" << _image << "i" << endl;}int getReal() const { return _real; }int getImage() const { return _image; }
private:int _real;int _image;
};
//运算符重载的第二种方式---普通函数
//在Complex类中提供一系列公有的get函数
//在这个函数中调用这些get函数能间接的获取到Complex私有成员 
//很少使用这种方式,因为几乎完全破坏了对私有成员的隐藏性
Complex operator+(const Complex& lhs, const Complex& rhs) {return Complex(lhs.getReal() + rhs.getReal(), lhs.getImage() + rhs.getImage());
}

成员函数形式 

class Complex {
public:Complex(int real, int image):_real(real), _image(image){}void print() {cout << _real << "+" << _image << "i" << endl;}//成员函数方式进行重载//会有一个默认的this指针作为第一个参数Complex operator+(const Complex& rhs) {return Complex(_real + rhs._real,_image + rhs._image);}
private:int _real;int _image;
};

在C++中,+运算符重载函数通常不返回引用,主要基于以下设计原则和实际需求:

//cx1.operator+(cx2)

一、语义一致性

  1. 数学加法特性
    +运算本质是生成新值而非修改原操作数,返回新对象符合数学加法语义。若返回引用,会误导使用者认为原对象被修改。

  2. 与内置类型行为对齐
    内置类型(如int)的+运算返回临时结果,自定义类型应保持相同行为以符合用户预期。

二、对象生命周期问题

  1. 临时对象必要性
    +运算结果通常是临时对象,若返回引用会绑定到即将销毁的局部对象(如函数栈内对象),导致悬垂引用。

    // 错误示例:返回局部对象引用
    const Vector& operator+(const Vector& v) {
       Vector tmp(v.x + 1, v.y + 1);
       return tmp; // tmp析构后引用失效
    }

  2. 无法返回成员对象引用
    若返回*this或其他成员引用,会破坏加法运算的交换律(如a+bb+a行为不一致)

三、性能与拷贝优化

  1. 返回值优化(RVO)
    现代编译器可优化临时对象的拷贝,直接构造返回值到目标位置,避免额外开销。

  2. 与赋值运算符对比
    赋值运算符(=)返回引用是为了支持链式赋值(如a=b=c,而+运算无此需求。

+=运算符重载 

像+=这一类会修改操作数的值的运算符,倾向于采用成员函数的方式重载

实现定义运算符重载函数步骤:

0.确定用什么方式重载

1.确定函数返回值

2.再写上函数名(operator运算符)

3.再补充参数列表(友元的普通函数---运算需要多少操作数就准备多少参数;成员函数---考虑第一个操作数是this指针所指向对象

4.最后完成函数体的内容

class Complex {
public:Complex(int real, int image):_real(real), _image(image){}void print() {cout << _real << "+" << _image << "i" << endl;}//成员函数方式进行重载//会有一个默认的this指针作为第一个参数Complex operator+(const Complex& rhs) {return Complex(_real + rhs._real,_image + rhs._image);}Complex& operator+=(const Complex& rhs) {_real += rhs._real;_image += rhs._image;return *this;}
private:int _real;int _image;
};
int main(void){Complex cx1(3, 7);Complex cx2(4, 5);cx1 += cx2;//本质cx1.operator+=(cx2);返回引用绑定的对象本身cx1.print();//7+12ireturn 0;
}

重载形式的选择(重要) 

不会修改操作数值的运算符,倾向于采用友元函数的方式重载

会修改操作数值的运算符,倾向于采用成员函数方式重载

具有对称性的运算符可能转换任意一端的运算对象,例如a+b(b+a一样),相等性,位运算符等,通常是友元

与给定类型密切相关的运算符,如递增,递减和解引用运算符,通常是成员函数形式重载

赋值=,下标[],调用(),成员访问->,成员指针访问->*运算符必须是成员函数形式重载

3.作业 

编写一个Base类使输出为1

class Base {
public:Base(int base):_base(base){}friendBase operator+(const Base& a, const Base& b);friendint operator==(const Base& a, int x);
private:int _base;
};
Base operator+(const Base& a, const Base& b) {return Base(b._base - a._base);
}
int operator==(const Base& a, int x) {return a._base == x;
}
int main(void) {int i = 2;int j = 7;Base x(i);Base y(j);cout << (x + y == j - i) << endl;return 0;
}

http://www.dtcms.com/a/481590.html

相关文章:

  • Qoder上线提示词增强功能,将开发者从 “提示词“ 的负担中解放出来
  • 「机器学习笔记15」深度学习全面解析:从MLP到LSTM的Python实战指南
  • 在ARM版MacBook上构建lldb-mi
  • php网站后台搭建html代码大全简单
  • 零基础新手小白快速了解掌握服务集群与自动化运维(十一)MySQL数据库主从复制
  • 云手机的真实体验感怎么样
  • 广州微网站建设信息电商如何做
  • 架设一个网站腾讯网站建设推广
  • 【数据结构】:链表的核心实现与操作解析
  • 【Verilog】系统任务和编译指令
  • 辅助分类器GAN(ACGAN)
  • 交流网站建设心得体会wordpress首页固定页面
  • 专门做有机食品的网站dedecms怎么部署网站
  • 大学生个体创业的网站建设百度搭建wordpress
  • 自己公司网站维护上海动易 网站
  • 摄影网站设计企业官网用什么系统
  • 网站开发工具最适合网站建设和网络优化
  • 东莞东坑网站设计中牟网站建设
  • 官方模板关键字生成的代码添加在网站的什么地方?郴州网站建设服务
  • 查看一个网站开发语言wap网站分享到微信
  • 网站备案流程教程今天的热点新闻
  • 网站站内链接福田欧曼前四后八
  • 网站建设具体方案免费企业邮箱排名
  • 温州建设小学的网站企业网站建设与实现的论文
  • 网站机房建设目的wordpress导航设置
  • 怎么构建网站wordpress 关闭伪静态
  • 做app推广上哪些网站做金融的看哪些网站
  • 机械设备做公司网站下载好了网站模板怎么开始做网站
  • 珠宝网站模板网络营销的概念与含义谷歌
  • 沧州网站建设联系电话做学徒哪个网站好