C++学习随笔之八:抽象与建模----类的设计技术
引言:本章的重点是类的设计技术,而不是通用原理
1.操作符(运算符)重载:
操作符重载本质(实质上)是一个函数(方法),不能重载基本类型的运行。语法为:
void operator+(const classs & i);
class c;
c.operator+(const class & i);//说明operator+ 就是个函数即: operator+()
几乎可以重载所有的c操作符,但是也有其限制,主要有以下一些限制:
(1)重载后的操作符必须至少有一个操作数是用户定义类型,这将防止用户为标准类型重载操作符
(2)使用操作符时不能违反操作符原来的语法规则,也不能修改操作符的优先级。
(3)不能定义不存在的操作符或新的操作符
(4)以下几个操作符不能重载:
sizeof——sizeof操作符
.——成员操作符
.*——成员指针操作符
::——作用域解析操作符
?:——条件操作符
typeid——一个RTTI操作符
const_cast——强制类型转换操作符
dynamic_cast——强制类型转换操作符
reinterpret——强制类型转换操作符
static_cast——强制类型转换操作符
可被重载的操作符如下表:
可被重载的操作符
(5)在上表中的大多数操作都可以通过成员或非成员函数进行重载,但下面的操作符只能通过成员函数来重载:
=——赋值操作符
()——函数调用操作符
[]——下标操作符
->——通过指针访问类成员的操作符
2.友元函数:
语法:在友元函数的声明中需要关键字friend ,而定义中不需要friend。虽然友元函数不是成员函数,但是它却与成员函数的访问权限一样。
知道了友元函数后,你可能以为友元破坏了OOP的数据隐藏原则,其实不然,而应该将友元看做一种类的扩展接口,它和类方法只是表达类接口的两种不同机制。
提示:如果要为类重载操作符,并将非类的项作为其第一个操作数,则可以用友元函数来反转操作数的顺序。
一般来说要重载<<操作符来显示c_name的对象,可使用一个友元函数,定义如下:
ostream & operator<<(ostream & os,const c_name & object)
{
os<<...;//显示对象内容
return os;
}
}
代码示例:
mytime3.h文件代码:
#include<iostream>
using namespace std;
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;
Time operator-(const Time & t)const;
Time operator*(double n)const;
friend Time operator*(double m,const Time & t)
{
return t*m;//调用operator*(double n)cosnt 成员函数
};
//<< 操作符重载,友元函数的应用 ,用<<操作符重载来显示 Time 对象的内容
friend ostream & operator<<(ostream & os ,const Time & t);
};
mytime3.cpp文件代码:
#include<iostream>
#include "mytime3.h"
using namespace std;
Time::Time()
{
hours=minutes=0;
}
Time::Time(int h,int m)
{
hours = h;
minutes = m;
}
void Time::AddHr(int h)
{
hours +=h;
}
void Time::AddMin(int m)
{
minutes +=m;
}
void Time::Reset(int h,int m)
{
hours = h;
minutes =m ;
}
Time Time::operator+(const Time & t)const
{
Time sum;
sum.minutes = minutes + t.minutes;
sum.hours = hours+t.hours+ sum.minutes/60;
sum.minutes %=60;
return sum;
}
Time Time::operator-(const Time & t)const
{
Time diff;
int tot1,tot2;
tot1=t.minutes +60*t.hours;
tot2=minutes + 60*hours;
diff.minutes = (tot2-tot1)%60;
diff.hours = (tot2-tot1)/60;
return diff;
}
Time Time::operator*(double mult)const
{
Time result;
long totalMinutes = hours*mult*60 + minutes*mult;
result.hours = totalMinutes/60;
result.minutes = totalMinutes%60;
return result;
}
//<< 操作符重载,友元函数的应用 ,用<<操作符重载来显示 Time 对象的内容
ostream & operator<<(ostream & os,const Time & t)
{
os << t.hours << " hours, "<< t.minutes << " minutes";
return os;
}
usetime3.cpp文件代码(主文件):
#include <cstdlib>
#include <iostream>
#include "mytime3.h"
using namespace std;
int main()
{
Time aida= Time(3,35);
Time tosca = Time (2,48);
Time temp;
cout <<"Aida and Tosca:\n";
cout << aida << "; " <<tosca <<endl;
temp = aida + tosca;
cout << "Aida + Tosca: "<<temp <<endl;
temp = aida - tosca;
cout <<"Aida - Tosca: " <<temp <<endl;
temp = aida * 1.17;
cout <<"Aida * 1.17: " <<temp<<endl;
cout <<"10 * Tosca: "<<10*tosca <<endl;
getchar();
return 0;
}
以上三个代码编译连接运行结果如下:
3.随即数函数 srand()和rand():
先从随机数的原理谈说起吧, 计算机的随机数都是由伪随机数,即是由小M多项式序列生成.产生每个小序列都有一个初始值,即随机种子. srand()产生随机种子. rand()产生随机数 srand()的函数定义为:void srand( unsigned int seed );要保证计算机产生不相同的随机数,应保证它们的随机种子是不一样的.srand((unsigned)time(NULL));就是以时间做为随机种子,因为每次你运行的时间总是不一样的. 也就是说 如果seed种子一样的话,用rand产生的随即数序列是一样的,故一般为了获取真正的随机数,所以采用时间做为srand()的种子。
代码示例:
#include<iostream>
using namespace std;
#include<cstdlib>
int main()
{
srand(time(0));
for(int i = 0; i < 10; i++ )
cout<<"随机数#"<<i <<": "<<rand()%20<<endl; //产生0-19之间的随机数
getchar();
return 0;
}
4.类的自动转换和强制类型转换
转换函数:是用户定义的强制类型转换,可以像使用强制类型转换那样使用,语法:operator typeName();typeName为要转换类型,比如说要将某类型转换为double 类型:operator double();但是转换函数必须满足一下三点:
a.转换函数必须是类方法
b.转换函数不能指定返回类型
c.转换函数不能有参数
当类定义了两种或者以上的转换函数时,通常使用显式调用转换函数,这样函数还能执行。
5.众所周知,所以可执行程序执行的第一个函数是main函数,但是有没有什么方法是得在main函数之前执行其他函数呢?答案是肯定的。全局对象(即具有文件作用域的对象)就可以实现这种技术,因为全局对象将在程序的main函数被调用之前创建,程序员可以创建一个类,其默认构造函数将调用所有的构造函数里的函数。代码示例:
class BeforeMain
{
private:
//..
public:
BeforeMain()
{
GetData();
...
}
}
};
BeforeMain test;
int main()
{
....
return 0;
}
6.小结:下面是一个复数运算的程序源代码,里面覆盖了 重载,友元,类型转换,自动类型转换等技术里,是本章技术的综合应用。
complex.h文件代码:
#include<iostream>
#include<cmath>
using namespace std;
class Complex
{
private:
double r;
double i;
public:
Complex();
Complex(double real);
Complex(double real,double imag);//复数
double Magnitude();//计算大小
Complex operator+(const Complex & c)const;
Complex operator-(const Complex & c)const;
Complex operator~()const;
friend Complex Square(const Complex & c);
friend Complex operator*(const Complex & a,const Complex & b);
friend ostream & operator<<(ostream & os,const Complex & c);
friend istream & operator>>(istream & is,Complex & c);
};
complex.cpp文件代码:
#include<iostream>
#include "complex.h"
using namespace std;
Complex::Complex()
{
r = i = 0.0;
}
Complex::Complex(double real)
{
r = real;
i = 0.0;
}
Complex::Complex(double real,double imag)
{
r = real;
i = imag;
}
double Complex::Magnitude()
{
return sqrt(r*r + i*i);
}
Complex Complex::operator+(const Complex & c)const
{
Complex add;
add.r = r + c.r;
add.i = i + c.i;
return add;
}
Complex Complex::operator-(const Complex & c)const
{
Complex sub;
sub.r = r - c.r;
sub.i = i - c.i;
return sub;
}
Complex Complex::operator~()const
{
Complex c;
c.r = r;
c.i = -i;
return c;
}
Complex Square(const Complex & c)
{
Complex square;
square.r = c.r * c.r - c.i * c.i;
square.i = 2.0 * c.r * c.i;
return square;
}
Complex operator*(const Complex & a,const Complex & b)
{
Complex mul;
mul.r = a.r * b.r - a.i * b.i;
mul.i = a.r * b.i + b.r * a.i;
return mul;
}
ostream & operator<<(ostream & os ,const Complex & c)
{
os << "("<<c.r<<","<<c.i <<"i)";
return os;
}
istream & operator>>(istream & is,Complex & c)
{
cout<<"real: ";
if(is>>c.r)
{
cout<<"imaginary: ";
is>>c.i;
}
return is;
}
主文件main函数文件代码:
#include <cstdlib>
#include <iostream>
#include "complex.h"
using namespace std;
int main(int argc, char *argv[])
{
Complex a = Complex(3.0,4.0);
Complex c ;
cout<<"Enter a complex number(q to quit): "<<endl;
while(cin>>c)
{
cout<<"c is "<< c<< endl;
cout<<"complex conjugate is " << ~c<<endl;
cout <<"a + c is " << a + c << endl;
cout <<"a - c is " << a - c << endl;
cout <<"a * c is " << a * c <<endl;
cout <<"2 * c is " << 2 * c <<endl;
cout <<"c * 2 is " << c * 2 <<endl;
cout <<"Enter a complex number(q to quit): "<<endl;
}
cout << "Done!" <<endl;
cin.get();
return 0;
}