使用类
运算符重载
? ? ? ?运算符是一种形式的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();
// 转换函数必须是类方法
// 不能指定返回类型
// 不能有参数
|