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;
}
posted @ 2013-03-17 19:28  Jamy Cai  阅读(463)  评论(0编辑  收藏  举报