C++ 第四周 第三部分

使用类

运算符重载

       运算符是一种形式的C++多态。实际上,很多C++运算符已经被重载,比如 * ,可以将它用于地址,也可以表示两个数字相乘。C++ 将运算符重载扩展到用户定义的类型

       要重载运算符,需要使用被称为运算符函数的特殊函数形式,格式如下:

operatorop(argument-list)

       例如:,operator +() 重载的是 + 运算符。op 必须是有效运算符,不能虚构出新的符号。燃鹅, operator [ ]()函数将重载 [ ] 运算符,因为 [ ] 是数组索引运算符。

       下面是一个示例:

// mytime.h
#ifndef MYTIME_H_
#define MYTIME_H_

class Time
{
	private:
		int hours;
		int minutes;
	public:
		Time();
		Time(int h,int m = 0);
		void AddMin(int m);
		void AddHr(int h);
		void Reset(int h = 0,int m = 0);
		Time operator+(const Time & t) const;    // 运算符重载
		void Show() const;
};
#endif
// mytime.cpp
#include<iostream>
#include "mytime.h"

Time::Time()
{
	hours = minutes = 0;
}

Time::Time(int h, int m)
{
	hours = h;
	minutes = m;
}

void Time::AddMin(int m)
{
	minutes += m;
	hours += minutes / 60;
	minutes %= 60;
}

void Time::AddHr(int h)
{
	hours += h;
}

void Time::Reset(int h, int m)
{
	hours += h;
	minutes = m;
}

Time Time::operator+(const Time & t) const
{
	Time sum;
	sum.minutes = minutes+ t.mintues;
	sum.hours = hours + t.hours + sum.minutes / 60;
	sum.minutes %= 60;
	return sum;
}

void Time::Show() const
{
	std::cout << hours << " hours, " << minutes << " minutes";
}

重载限制

       1. 重载后的运算符必须至少有一个操作数是用户定义的类型这将防止用户为标准类型重载运算符。因此,不能将减法运算符重载为计算两个double 值的和。这将保证程序正常运行。

       2. 使用运算符不能违法运算符原来的句法规则。例如,不能将求模运算符(%)重载成使用一个操作数:

int x;
Time shvia;
& x;        // invalid
% shvia     // invalid

        同样,不能修改运算符的优先级。

        3.  不能创建新的运算符。例如,不能定义 operator ** () 函数来表示求幂。

        4. 不能重载下面的运算符:

sizeof
.                
.*                //  成员指针运算符 
::
?:
typeid            // 一个 RTTI 运算符 

// 下面四个都是强制类型转换运算符 
// 用法: 强制类型转换运算符 <typename> (expression) 

const_cast        // const_cast<>里边的内容必须是引用或者指针

reinterpret_cast  // 1 改变指针或引用的类型
                  // 2 将指针或引用转换为一个足够长度的整形
                  // 3 将整型转换为指针或引用类型
                  
dynamic_cast      // 1 其他三种都是编译时完成的,dynamic_cast 是运行时处理的,运行时要进行类型检查
                  // 2 不能用于内置的基本数据类型的强制转换
                  // 3 dynamic_cast 要求 <> 内所描述的目标类型必须为指针或引用
                  // 4 使用 dynamic_cast 进行转换的,基类中一定要有虚函数,否则编译不通过
                  
static_cast       // 基本数据类型之间的转换 

         下面的运算符只能通过成员函数就行重载:

=
()
[]
->

 

友元

       C++ 控制对类对象私有部分的访问。通常,公有类方法提供了唯一的访问途径,但有时候这种限制不合理。C++ 提供另一种形式的访问权限:友元。

       友元有三种:

1. 友元函数;

2. 友元类

3. 友元成员函数.

创建友元

      创建友元函数的第一步是将其原型放在类声明中,并再原型声明前加上关键字 friend:

friend Time operator* (double m, const Time & t);

      该原型意味着下面两点:

1. 虽然 operator* () 函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;

2. 虽然 operator* () 函数不是成员函数,但它的访问权限与之成员函数相同.

 

      第二步,函数定义不要使用关键字 friend,不要使用 Time : : 限定符:

Time operator* (double m, const & t)
{
	Time result;
	long totalminutes = t.hours * m * 60 + t.minutes * m;
	result.hours = totalminutes / 60;
	result.minutes = totalminutes % 60;
	return result;
}

        实际上,按下面的方式对定义进行修改(交换乘法操作数的顺序),可以将这个友元函数编写为非友元函数:

Time operator* (double m, const & t)
{
	return t * m;
}

         提示:如果要为类 重载 运算符,并将非类的项作为其第一个操作数,则可以用友元函数来反转操作数的顺序.

重载 << 运算符

  

<< 的第一种版本

       要使 Time 类知道使用 cout , 必须使用友元函数。这是什么原因呢?因为下面这样的语句使用俩个对象,其中第一个是 ostream 类对象(cout):

cout << trip;

       如果使用一个 Time 成员函数来重载 << ,Time 对象将是一个操作数,就像使用成员函数重载

 * 运算符那样。这意味着必须这样使用 << :

trip << cout;  // if operator<<() were a Time member function

       这样会令人疑惑。但通过友元函数,可以像下面这样重载运算符:

void operator<<(ostream & os, const Time & t)
{
	os << t.hours << " hours, " << t.minutes << " minutes";
}

        这样可以使用下面的语句:

cout << trip;

 

<< 的第二种重载版本

 

重载运算符:作为成员函数还是非成员函数

 

 

一个矢量类

       直接上代码

// vect.h
#ifndef VECTOR_H_
#define VECTOR_H_
#include<iostream>
name space VECTOR
{
	class vector
	{
		public:
			enum Mode (RECT, POL);
		private:
			double x;         // horizontal value 
			double y;         // vertical value
			double mag;       // lenth of vector
			double ang        // direction of vector in degrees
			Mode mode;        // RECT of POL
			void set_mag();
			void set_ang();
			void set_x();
			void set_y();
		public:
			Vector();
			 Vector(double n1, double n2, Mode form = RECT);
			 void reset(double n1, double n2, Mode form = RECT);
			 ~Vector();
			 double xval() const (return x;)
			 double yval() const (return y;)
			 double magval() const (return mag;)
			 double angval() const (return ang;)
			 void polar_mode();               // set mode to POL
			 void rect_mode();                // set mode to RECT
	    // operator overloading
	        Vector operator+(const Vector & a) const;
	        Vector operator-(const Vector & b) const;
	        Vector operator-() const;
	        Vector operator*(double n) const;
	    // friends
	        friend Vector operator*(double n, cosnt Vector & a);
	        friend std::ostream &
	               operator<<(std::ostream & os, const Vector & v);
	};
}
#endif
// vect.cpp
#include<cmath>
#include "vect.h"
using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
	const double Rad_to_deg = 45.0 / atan(1.0);

	void Vector::set_mag()
	{
		mag = sqrt(x * x * y * y);
	}

	void Vector::set_ang()
	{
		if(x == 0.0 && y == 0.0)
		{
			ang = 0.0;
		}
		else
		{
			ang = atan2(y, x);
		}
	}

	void Vector::set_x()
	{
		x = mag * cos(ang);
	}

	void Vector::set_y()
	{
		y = mag * sin(ang);
	}
    
    // public method
	Vector::Vector()
	{
        x = y = mag = ang = 0.0;
        mode = RECT;
	}
	
	Vector::Vector(double n1, double n2, Mode form)
	{
		mode = form;
		if(form == RECT)
		{
			x = n1;
			y = n2;
			set_mag();
			set_ang();
		}
		else if(form == POL)
		{
			mag = n1;
			ang = n2;    // Rad_to_deg
			set_x();
			set_y();
		}
		else
		{
			cout << "Incorrent 3rd argument to Vector() == ";
			cout << "vetcor set to 0\n";
			x = y = mag = deg = 0.0;
			mode = RECT;
		} 
	}
	
	void Vector:: reset(double n1, double n2, Mode form)
	{
		mode = form;
		if(form == RECT)
		{
			x = n1;
			y = n2;
			set_mag();
			set_ang();
		}
		else if(form == POL)
		{
			mag = n1;
			ang = n2;
			set_x();
			set_y();
		}
		else
		{
			cout << "Incorrent 3rd argument to Vector() == ";
			cout << "vetcor set to 0\n";
			x = y = mag = deg = 0.0;
			mode = RECT;
		}
	}
	
	Vector:~Vector()
	{
	}
	
	void Vector::polar_mode()
	{
		mode = POL;
	}
	
	void Vector::rect_mode()
	{
		mode = RECT;
	}
	
	Vector Vector::operator+(const Vector & b) const
	{
		return Vector(x + b.x, y + b.y);
	}
	
	Vector Vector::operator-(const Vector & b) const
	{
		return Vector(x - b.x, y - b.y);
	}
	
    Vector Vector::operator-() const
    {
    	return Vector(-x, -y);
	}
	
	Vector Vector::operator*(double n) const
	{
		return Vector(n * x, n * y);
	}
	
	// friend methods
	Vector operator*(double n, const Vector & a)
	{
		return a * n;
	}
	
	std::ostream & operator<<(std::ostream & os, const Vector & v)
	{
		if(v.mode == Vector::RECT)
		{
			os << "(x,y) = (" << v.x << ", " << v.y << ")";  
		}
		else if(v.mode == Vector::POL)
		{
			os << "(m,a) = (" << v.mag << ", 
			    << v.ang * Rad_to_deg << ")";
		}
		else
		{
			os << "Vector object mode is invalid";
		}
		return os;
	}
}

 

 

 

 

转换函数

       格式:

operator typeName();
// 转换函数必须是类方法
// 不能指定返回类型
// 不能有参数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DDsoup

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值