1.运算符重载
为什么要对运算符进行重载?
C++中预定义的运算符的操作对象仅限于基本的内置数据类型,而对于我们自定义的类型(类)是没有办法操作的。但是大多数时候我们需要对我们定义的类型进行运算,这个时候就需要我们对这些 运算符进行重新定义,赋予其新的功能,以满足自身的需求。
a.流运算符的重载
注意:
1.由于ostream类型已经在iostream中实现,所以不能作为ostream类的成员函数重载,只能作为全局函数或友元函数重载。
流运算符为什么不能重载为成员函数,只能用友元函数重载
2.cout 是在 iostream 头文件中定义的 ostream 类的对象。
因此重载运算符时
istream & operator >> (istream &, 自定义类 &);
ostream & operator << (ostream &, 自定义类 &);
为了避免产生歧义,第一个参数最好不要直接写成cout或cin
ostream & operator<<(ostream & cout, const CStudent & s) {//此处为了节省运行时间,使用了CStudent &
cout << s.age;
return cout;
}
最好写为
ostream & operator<<(ostream & o, const CStudent & s) {//此处为了节省运行时间,使用了CStudent &
o << s.age;
return o;
}
3.流提取和流插入运算符的重载函数的返回值必须是istream或ostream类的引用
istream & operator >> (istream &, 自定义类 &);
ostream & operator << (ostream &, 自定义类 &);
原因:返回类型为引用是为了能够连续的输入输出,第一个参数类型为引用是为了将实参cout直接传给形参,以便带回重载后修改的值。
b.特殊运算符的重载
C++规定有四个运算符 =, ->, [], ()不可以是全局域中的重载(即不能重载为友员函数)理解。
运算符的意义:
在C++中,运算符重载是很重要的、很有实用意义的。它使类的设计更加丰富多彩,扩大了类的功能和使用范围,使程序易于理解, 易于对对象进行操作,它体现了为用户着想、方便用户使用的思想。有了运算符重载,在声明了类之后,人们就可以像使用标准类型一样来使用自己声明的类。类的声明往往是一劳永逸的,有了好的类,用户在程序中就不必定义许多成员函数去完成某些运算和输入输出的功能,使主函数更加简单易读。好的运算符重载能体现面向对象程序设计思想。
在运算符重载中使用引用(reference)的重要性。
利用引用作为函数的形参可以在调用函数的过程中不是用传递值的方式进行虚实结合,而是通过传址方式使形参成为实参的别名,因此不生成临时变量(实参的副本),减少了时间和空间的开销。
此外,如果重载函数的返回值是对象的引用时,返回的不是常量,而是引用所代表的对象,它可以出现在赋值号的左侧而成为左值(left value),可以被赋值或参与其他操作(如保留cout流的当前值以便能连续使用“<<”输出)。但使用引用时要特别小心,因为修改了引用就等于修改了它所代表的对象。
2.c++中return this和return *this的区别
this是指向自身对象的指针,*this是自身对象。
也就是说return *this返回的是当前对象的克隆或者本身(若返回类型为A, 则是克隆, 若返回类型为A&, 则是本身 )。
return this返回当前对象的地址(指向当前对象的指针)
return *this和return this有什么区别?
3.常变量(引用)与非常变量(引用)
C++ “const常变量”与“非常变量(普通变量)”间的赋值
常变量不能传值给非常引用
4.临时对象
临时对象是通过调用拷贝构造函数产生的,故使用引用来减少临时对象的产生可以提高程序性能
5.类初始化列表
一个好的原则是,能使用初始化列表的时候尽量使用初始化列表.
避免在调用构造函数时产生临时对象的方法是使用类初始化列表
c++中的初始化列表详解
6.常引用做参数
引用型参数应该在能被定义为const的情况下,尽量定义为const 。
引用作为函数参数和常引用作为函数参数
C++中一般引用作形参和常引用作形参的问题
7.实例
#include<iostream>
#include<iomanip>
using namespace std;
class Point {
double _x, _y;
int count;
static int sum;
public:
Point(double a, double b) {
_x = a;
_y = b;
// cout << "Point : (" << x << ", " << y << ") is created." << endl;
sum++;
count = sum;
}
Point(double a) {
_x = a;
_y = a;
//cout << "Point : (" << x << ", " << y << ") is created." << endl;
sum++;
count = sum;
}
Point() {
_x = 0;
_y = 0;
//cout << "Point : (" << x << ", " << y << ") is created." << endl;
sum++;
count = sum;
}
Point(const Point& p) {
_x = p._x;
_y = p._y;
//cout << "Point : (" << x << ", " << y << ") is copied." << endl;
sum++;
count = sum;
}
~Point() {}
//Point::show()方法:按输出格式输出Point对象。
void show() const{
cout << "Point[" << count << "]" << ": (" << setprecision(16) << _x << ", " << setprecision(16) << _y << ")" << endl;
}
//Point::showSumOfPoint()方法:按格式输出程序运行至当前存在过的Point对象总数。
static int showSumOfPoint() {
cout << setprecision(16) << "In total : " << sum << " points." << endl;
return sum;
}
//Point::x()方法:取x坐标。
double x() const{
return _x;
}
//Point::y()方法:取y坐标。
double y() const{
return _y;
}
//Point::x(double)方法:传参数设置x坐标并返回。
double x(double xx) {
_x = xx;
return _x;
}
// Point::y(double)方法:传参数设置y坐标并返回。
double y(double yy) {
_y = yy;
return _y;
}
// Point::setPoint(double, double)方法:设置Point对象的x坐标(第一个参数)和y坐标(第二个参数)并返回本对象
Point& setPoint(double xxx, double yyy) { //若返回类型为A, 则是克隆, 若返回类型为A&, 则是本身
this->_x = xxx;
this->_y = yyy;
return *this;
}
//Point::isEqual()方法:判断传入的参数与对象的坐标是否相同,相同返回true。
bool isEqual(Point &p) const{//-4,使用引用不会创建临时对象
if (this->_x == p._x && this->_y == p._y) {
return true;
}
else return false;
}
//Point::copy()方法:传参数复制给对象。
Point& copy(Point &p1) {//-3,使用引用不会创建临时对象
this->_x = p1._x;
this->_y = p1._y;
return *this;
}
//Point::inverse()方法,有两个版本:不传参数则将对象自身的x坐标和y坐标互换;若将Point对象做参数传入,则将传入对象的坐标交换复制给对象自身,不修改参数的值。
Point& inverse() {
double t;
t = this->_x;
this->_x = this->_y;
this->_y = t;
return *this;
}
Point& inverse(Point &p2) {//-1,使用引用不会创建临时对象
this->_x = p2._y;
this->_y = p2._x;
return *this;
}
//传递和返回引用是不构造新对象的。给函数正确的返回值。
//注意常量对象调用的函数。
};
int Point::sum = 0;
//在引用前面加上const,代表该引用为常引用,即被引用的对象不可改变。若是在形参中使用,则不可达到在函数里面修改变量值的目的。
//这里若使用普通变量,则会创建一个临时对象用来调用,解决方法:使用常引用
void ShowPoint(const Point &p)//-1,使用引用不会创建临时对象
{
cout << std::setprecision(16) << "Point : (" << p.x() << ", " << p.y() << ")" << endl;
}
void ShowPoint(double x, double y)
{
//Point p(x, y);
//cout << std::setprecision(16) << "Point : (" << p.x() << ", " << p.y() << ")" << endl;
cout << std::setprecision(16) << "Point : (" << x << ", " << y << ")" << endl;
}
int main()
{
int l(0);
char c;
double a, b;
Point p, q, pt[60];
while (std::cin >> a >> c >> b)
{
if (a == b)
p.copy(pt[l].setPoint(a, b));
if (a > b)
p.copy(pt[l].setPoint(a, b).inverse());
if (a < b)
p.inverse(pt[l].setPoint(a, b));
if (a < 0)
q.copy(p).inverse();
if (b < 0)
q.inverse(p).copy(pt[l]);
pt[l++].show();
p.show();
}
q.show();
cout << "==========gorgeous separator==========" << endl;
double x(0), y(0);
for (int i = 0; i < l; i++)
x += pt[i].x(), y -= pt[i].y();
pt[l].x(y), pt[l].y(x);
q.copy(pt[l]).show();
for (int i = 0; i <= l; i++)
pt[i].show();
cout << "==========gorgeous separator==========" << endl;
const Point const_point(3, 3);
const_point.show();
for (int i = 0; i <= l; i++)
{
if (const_point.isEqual(pt[i]))
{
ShowPoint(const_point);
ShowPoint(const_point.x(), const_point.y());
ShowPoint(Point(const_point.x(), const_point.y()));
}
}
const_point.showSumOfPoint();
}
//能用引用就用引用,并且要检查某处是否多创了一个对象
/*
1,2
3,3
2,1
*/