Day42、操作符重载、继承、向上造型

来源:互联网 发布:淘宝零食可以买吗 编辑:程序博客网 时间:2024/05/07 03:21

练习:

实现3*3矩阵类,支持如下操作符:

+  - +=   -=

 

#include<iostream>

#include<iomanip>//setw()设置域宽

using namespace std;

class M33{

public:

   M33(void){

       for(int i=0;i<3;i++)

           for(int j=0;j<3;j++)

                m_a[i][j]=0;

    }

   M33(int a[][3]){

       for(int i=0;i<3;i++)

           for(int j=0;j<3;j++)

                m_a[i][j]=a[i][j];

    }

   friend ostream& operator<<(ostream& os,const M33& m){

       for(int i=0;i<3;i++){

           for(int j=0;j<3;j++)

                os<<setw(4)<<m.m_a[i][j];

                os<<endl;

       }

   return os;

    }

   const M33 operator+(const M33& m)const{

       int a[3][3]={};

       for(int i=0;i<3;i++)

           for(int j=0;j<3;j++)

                a[i][j]=m_a[i][j]+m.m_a[i][j];

       return a; //return M33(a);

    }

   const M33 operator-(const M33& m)const{

       int a[3][3]={};

       for(int i=0;i<3;i++)

           for(int j=0;j<3;j++)

                a[i][j]=m_a[i][j]-m.m_a[i][j];

       return a; //return M33(a);

    }

   const M33 operator*(const M33& m)const{

       int a[3][3]={};

       for(int i=0;i<3;i++)

           for(int j=0;j<3;j++)

                for(int k=0;k<3;k++)

                   a[i][j]+=m_a[i][k]*m.m_a[k][j];

       return a; //return M33(a);

    }

    //+ - *返回值右值,左操作数必须是左值,右操作数可以为左值,也可以为右值

   M33& operator+=(const M33& m){

       return *this=*this + m;

    }

   M33& operator-=(const M33& m){

       return *this=*this - m;

    }

   M33& operator*=(const M33& m){

       return *this=*this * m;

    }

private:

   int m_a[3][3];

};

int main(){

   int a1[3][3]={1,2,3,4,5,6,7,8,9};

   int a2[3][3]={9,8,7,6,5,4,3,2,1};

   M33 m1(a1);

   M33 m2(a2);

   cout<<m1<<endl;

   cout<<m2<<endl;

   cout<<"m1+m2"<<endl;

   cout<<m1+m2<<endl;

   cout<<"m1-m2"<<endl;

   cout<<m1-m2<<endl;

   cout<<"m1*m2"<<endl;

   cout<<m1*m2<<endl;

   cout<<"m1+=m2"<<endl;

   cout<<(m1+=m2)<<endl;

   cout<<"m1-=m2"<<endl;

   cout<<(m1-=m2)<<endl;

   cout<<"m1*=m2"<<endl;

   cout<<(m1*=m2)<<endl;

   return 0;

}

tarena@tarena-virtual-machine:~/day42$./a.out

  1   2   3

  4   5   6

  7   8   9

 

  9   8   7

  6   5   4

  3   2   1

 

m1+m2

 10  10  10

 10  10  10

 10  10  10

 

m1-m2

  -8  -6  -4

 -2   0   2

  4   6   8

 

m1*m2

 30  24  18

 84  69  54

 138114  90

 

m1+=m2

 10  10  10

 10  10  10

 10  10  10

 

m1-=m2

  1   2   3

  4   5   6

  7   8   9

 

m1*=m2

 30  24  18

 84  69  54

 138114  90

3、(操作符重载,接昨天)单目操作符重载:#O

3.1 计算类的单目操作符(~ 、 !…) !a, ~a ; -a; &a ;

1)成员函数形式

#O==》O.operator#( )

2)全局函数形式

#O==》::operator#(0)

举例:

  1#include<iostream>

  2using namespace std;

  3class Integer{

  4public:

 5     Integer(int i=0):m_i(i){}

 6     const Integeroperator-(void)const{//取负操作符重载

 7         return Integer(-m_i);

 8     }

 9     //自定义~表示乘方

 10    friend const Integer operator~(const Integer& i){

 11        return Integer(i.m_i*i.m_i);

 12     }

 13    friend ostream& operator<<(ostream& os,const Integer&i){

 14        os<<i.m_i;

 15     }

 16private:

 17    int m_i;

 18};

 19int main(void){

 20    Integer i(100);

 21    Integer j=-i;

 22    cout<<i<<endl;//-100

 23    cout<<j<<endl;//-100

24     j=~i;

 25    cout<<j<<endl;//10000

 26     return 0;

 27 }

 

3.2自增减操作符

1)前缀自增减

成员函数:  #O==》O.operator#( )

全局函数:  #O==》::operator#(0)

++n;  操作数必须是左值,返回值就是操作数自身也是左值

2)后缀自增减

成员函数:  #O==》O.operator#( int)

全局函数:  #O==》::operator#(0,int)

int num=10;

num++;

num ; 11

操作数必须是左值,返回值是右值,是自增减之前的副本

举例:

  1#include<iostream>

  2using namespace std;

  3class Integer{

  4public:

 5     Integer(int i=0):m_i(i){}

 6     //前++  (可以用友元) 成员函数

 7     Integer&operator++(void){

 8         ++m_i;

 9         return *this;

 10     }

 11    //前--  全局函数

 12    friend Integer& operator--(Integer& i){

 13        --i.m_i;

 14        return i;

 15     }

 16    //后++   (可以用友元friend,这样也可以)

 17    const Integer operator++(int){

 18        Integer old=*this;

 19        ++*this;//复用前++

 20        return old;

 21     }

 22    //后--

 23     friend const Integeroperator--(Integer& i,int){

24         Integer old=i;

 25        --i;

 26        return old;

 27     }

 28    friend ostream& operator<<(ostream& os,const Integer&i){

 29        os<<i.m_i;

 30     }

 31private:

 32    int m_i;

 33};

 34int main(void){

 35    Integer i(123);

 36    Integer j=++i;

 37    cout<<"i="<<i<<endl;//124

 38    cout<<"j="<<j<<endl;//124

39     j=++++++i;

 40    cout<<"i="<<i<<endl;//127

 41    cout<<"j="<<j<<endl;//127

 42

 43    j=i++;

 44    cout<<"i="<<i<<endl;//128

 45    cout<<"j="<<j<<endl;//127

 46

 47    j=--i;

 48    cout<<"i="<<i<<endl;//127

 49    cout<<"j="<<j<<endl;//127

 50

 51    j=i--;

 52    cout<<"i="<<i<<endl;//126

 53    cout<<"j="<<j<<endl;//127

 54    return 0;

 55 }

4、函数操作符:()(少用!)

如果一个类重载了函数操作符,那么该类的对象就可以当做函数来调用,其参数和返回值就是函数操作符函数的参数和返回值

  1#include<iostream>

  2using namespace std;

  3class Square{

  4public:

 5     double operator()(doublex)const{

 6         return x*x;

 7     }

 8     int operator()(int a,intb,int c=9){

 9         return a+b-c;

 10     }

 11};

 12int main(void){

 13    Square square;

 14    cout<<square(13.)<<endl;//square.operator()(13.)

 15    cout<<square(10,40,20)<<endl;//30

 16    cout<<square(10,40)<<endl;//41

 17    return 0;

 18 }

5、下标操作符,[]

int arr[5]={1,2,3,4,5};

arr[1]=20;

cosnt int (rarr)[5]= arr;

rarr[1]=20;//error

举例:

  1#include<iostream>

  2using namespace std;

  3class Array{

  4public:

 5     Array(int size):m_data(newint[size]),m_size(size){}

 6     ~Array(void){

 7         delete[] m_data;

 8         m_data=0;

 9     }

 10    int& operator[](int i){//非常对象调用

 11        return m_data[i];

 12     }

 13    const int& operator[](int i)const{//常对象调用

 14        //return m_data[i];

 15        //直接复用上面的非常版本

 16         returnconst_cast<Array&>(*this)[i];

 17     }

 18private:

 19    int * m_data;

 20    int m_size;

 21};

 22int main(void){

 23    Array a(10);

24    a[0]=10;//a.operator[](0)->a.m_data[0]=10

 25    a[1]=20;

 26    cout<<a[0]<<','<<a[1]<<endl;//10,20

 27    const Array& ra=a;

 28    cout<<ra[0]<<','<<ra[1]<<endl;//10,20

 29    //ra[0]=11; error const修饰不能修改值

 30    //ra[1]=12; error

 31    return 0;

 32 }

 

6、解引用和间接成员访问操作符: *->

用于实现智能指针:一个封装常规指针的类类型对象,当它离开作用域时,其析构函数负责释放该常规指针所指向的动态内存,避免内存泄露。

代码:

  1#include<iostream>

  2using namespace std;

  3class A{

  4public:

 5     A(void){

 6         cout<<"A::A()"<<endl;

 7     }

 8     ~A(void){

 9        cout<<"A::~A()"<<endl;

 10     }

 11};

 12class PA{

 13public:

 14    PA(A* pa=NULL):m_pa(pa){}

 15    ~PA(void){

 16        if(m_pa){

 17            delete m_pa;    //释放栈区空间

 18            m_pa=NULL;

 19        }

 20     }

 21private:

 22    A* m_pa;

 23};

24 int main(void){

 25    //A a;

 26    //A* pa=new A;

 27    PA pa(new A);//栈区对象

 28    return 0;//智能指针:析构函数一定会被调用,防止内存泄露

 29 }

tarena@tarena-virtual-machine:~/day42$./a.out

A::A()

A::~A()

实际使用:

#include<iostream>

#include<memory>

using namespace std;

class A{

public:

   A(const string& str):m_str(str){

       cout<<"A::A()"<<endl;

   }   

   ~A(void){

       cout<<"A::~A()"<<endl;

   }  

   string m_str;

};

class PA{

public:

   PA(A* pa=NULL):m_pa(pa){}

   ~PA(void){

       if(m_pa){

           delete m_pa;    //释放栈区空间

           m_pa=NULL;

       }

    }

   A* operator->(void)const{

       return m_pa;

    }

   A& operator*(void)const{

       return *m_pa;

    }

private:

   A* m_pa;

};

int main(void){

   //A a;

   //A* pa=new A;

#if 0

   PA pa(new A("hello world"));//栈区对象

   //pa.operator->()->m_str;

   cout<<pa->m_str<<endl;

   //pa.operator*().m_str;

   cout<<(*pa).m_str<<endl;

#else

   auto_ptr<A> pa(new A("hello world!"));//内部自动封装了只能指针

   cout<<pa->m_str<<endl;

   cout<<(*pa).m_str<<endl;

#endif

   return 0;//智能指针:析构函数一定会被调用,防止内存泄露

}

7、类型转换操作符

1)通过构造函数实现自定义类型转换

基本类型-à类类型

Integer i (100);

//int -> Integer

i=200;//通过类型转换构造函数

2)通过类型转换操作符函数实现自定义类型转换

operator 目标类型(void)const { }

类类型à基本类型

//Integer àint

int i2=i ;//类型转换操作符函数 

3)如果两个类型都是基本类型,无法转换

4)如果两个类型都是自定义类型,两种方式都可以

例:

  1#include<iostream>

  2using namespace std;

  3class Integer{

  4public:

 5     //int ---> Integer

 6     Integer(int data=0):m_data(data){

 7         cout<<"类型转换构造函数"<<endl;

 8     }

 9     operator int(void)const{

 10        cout<<"类型转换操作符函数"<<endl;

 11        return m_data;

 12     }

 13private:

 14    int m_data;

 15};

 16int main(){

 17    Integer i1(100);//构造函数

 18    i1=200;//类型转换构造函数,把i1转换成整型数

 19    cout<<i1<<endl;//200  操作符函数

 20    int i2=i1;//操作符函数

 21    cout<<i2<<endl;//200

 22    return 0;

 23 }

类型转换构造函数

类型转换构造函数

类型转换操作符函数

200

类型转换操作符函数

200

 

8、new/delete 操作符

static void* operator new(size_t size){….}

static void operator delete(void *p){….}

举例:

  1#include<iostream>

  2#include<cstdlib>

  3using namespace std;

  4class A{

  5public:

 6     A(void){

 7        cout<<"A::A()"<<endl;

 8     }

 9     ~A(void){

 10        cout<<"A::~A()"<<endl;

 11     }

 12    static void* operator new(size_t size){

 13        cout<<"A::new"<<endl;

 14        void *pv=malloc(size);

 15        return pv;

 16     }

 17    static void operator delete(void* pv){

 18        cout<<"A::delete"<<endl;

 19        free(pv);

 20     }

 21};

 22int main(){

 23    //1)分配内存

 24     //A* pa=(A*)A::operator new(sizeof(A));

 25    //2)pa->A();

 26    A* pa=new A;

 27

 28    //1)pa->~A();

 29    //2)释放内存

 30    //A::operator delete(pa);

 31    delete pa;

 32     return0;

 33 }

9、操作符重载限制

1)不是所有的操作符都能重载,下列操作符无法重载:

 作用域限定操作符:“::”

 直接成员访问操作符:“.”

 直接成员指针解引用操作符:“.*”

 条件操作符:“?”

 字节长度操作符:“sizeof( )”

 类型信息操作符:“typeid”

2)如果一个操作符所有的操作数都是基本类型,则无法重载

3)操作符重载不会改变编译器预定义的优先级

4)操作符重载无法改变操作数的个数

5)无法通过操作符重载发明新的操作符

6)操作符重载完全可以用普通成员函数来替换

一、继承(重点)!!!!Inheritance

1、继承的基本概念

 通过一种机制表达类型之间共性和特性的方式,利用已有数据类型定义新的数据类型,这种机制就是继承。

人类:姓名、年龄、吃饭、睡觉

学生类:姓名、年龄、学号、吃饭、睡觉、学习

教师类:姓名、年龄、工资、吃饭、睡觉、讲课

 

人类:姓名、年龄、吃饭、睡觉

学生类继承人类:学号、学习

教师类继承人类:工资、讲课

 

   人类(基类/父类)

  /        \

学生类    教师类(派生类/子类)

基类派生子类,子类继承基类

2、继承的语法形式

class 子类:继承方式1  基类1,继承方式2,基类2……{

…..

}

继承方式:

public :公有继承

protected :保护继承

private:私有继承

 

class Human{};

class Student:public Human{

       //Student类继承了Human类

       //Student类存在一份Human中的成员

};

举例

#include<iostream>

using namespace std;

//人类(基类)

class Human{

public:

   Human(const string& name,int age)

       :m_name(name),m_age(age){}//初始化

   void eat(const string& food)const{//常函数(const *this)不需要修改成员变量

       cout<<"我在吃"<<food<<endl;

    }

   void sleep(int time)const{

       cout<<"我睡了"<<time<<"小时"<<endl;

    }

protected: //保护成员可以在子类中访问,外部不能访问

   string m_name;

   int m_age;

};

//学生类(人类派生的子类)

class Student:public Human{

public:

   Student(const string& name,int age,int no):

       Human(name,age),m_no(no){}//初始化

   void who(void)const{//不修改成员变量的都尽量使用常函数

       cout<<"我叫"<<m_name<<",今年"<< \

           m_age<<"岁,学号"<<m_no<<endl;

    }

   void learn(const string& course)const{

       cout<<"我在学"<<course<<endl;

    }

private:

   int m_no;

};

//教师类(人类派生的另外一个子类)

class Teacher:public Human{

public:

    Teacher(conststring& name,int age,double salary):

       Human(name,age),m_salary(salary){}

   void teach(const string& course)const{

       cout<<"我在讲"<<course<<endl;

    }

   void who(void)const{

       cout<<"我叫"<<m_name<<",今年"<< \

           m_age<<"岁,工资:"<<m_salary<<endl;

    }

private:

   double m_salary;

};

int main(void){

   Student s("悟空",30,10001);

   s.who();

   s.eat("桃子");

   s.sleep(8);

   s.learn("打坐");

   Teacher t("唐僧",31,5000.5);

   t.who();

   t.eat("蔬菜");

   t.sleep(6);

   t.teach("佛法");

   return 0;

}

tarena@tarena-virtual-machine:~/day42$./a.out

我叫悟空,今年30岁,学号10001

我在吃桃子

我睡了8小时

我在学打坐

我叫唐僧,今年31岁,工资:5000.5

我在吃蔬菜

我睡了6小时

我在讲佛法

3、公有继承的特性

3、1共同性:任何时候子类对象都可以看做是一个基类对象

32向上造型(重点)

将子类类型的指针或引用转换成基类类型的指针或引用。

(将学生类型转换成老师类型)

这种转换缩小了指针或引用操作范围,在编译看来是安全的,所以可以隐式转换。

#include<iostream>

using namespace std;

//人类(基类)

class Human{

public:

   Human(const string& name,int age)

       :m_name(name),m_age(age){}//初始化

   void eat(const string& food)const{//常函数(const *this)不需要修改成员变量

       cout<<"我在吃"<<food<<endl;

    }

   void sleep(int time)const{

       cout<<"我睡了"<<time<<"小时"<<endl;

    }

protected: //保护成员可以在子类中访问,外部不能访问

   string m_name;

   int m_age;

};

//基类子对象:子类对象中包含基类的部分

//学生类(人类派生的子类)

class Student:public Human{

public:

   Student(const string& name,int age,int no):

       Human(name,age),m_no(no){}//初始化

   void who(void)const{//不修改成员变量的都尽量使用常函数

       cout<<"我叫"<<m_name<<",今年"<< \

           m_age<<"岁,学号"<<m_no<<endl;

    }

   void learn(const string& course)const{

       cout<<"我在学"<<course<<endl;

    }

private:

   int m_no;

};

//教师类(人类派生的另外一个子类)

class Teacher:public Human{

public:

   Teacher(const string& name,int age,double salary):

       Human(name,age),m_salary(salary){}

   void teach(const string& course)const{

       cout<<"我在讲"<<course<<endl;

    }

   void who(void)const{

       cout<<"我叫"<<m_name<<",今年"<< \

           m_age<<"岁,工资:"<<m_salary<<endl;

    }

private:

   double m_salary;

};

int main(void){

   Student s("悟空",30,10001);

   s.who();

   s.eat("桃子");

   s.sleep(8);

   s.learn("打坐");

   Teacher t("唐僧",31,5000.5);

   t.who();

   t.eat("蔬菜");

   t.sleep(6);

   t.teach("佛法");

 

   //向上造型,缩小了指针的操作范围,所以安全,可以做隐式类型转换

   //(12个字节只访问前8个字节,安全!)

   Human* ph=&s; //ph指向子类对象的基类指针

   ph->eat("桃");//可以访问基类中有的部分

   ph->sleep(10);//可以访问基类中有的部分

   //ph->who();

   return 0;

}

 

图:向上造型

 

 

练习:M33矩阵类让它增加支持如下操作符:

前后++  前后--   取负(让无参构造对象减去有参构造对象)、取下标[ ]值

arr[1][1]=>*(arr+1)[1]=>*(*(arr+1)+1)

 

 

#include <iostream>

#include <iomanip>//setw()设置域宽

using namespace std;

 

class M33{

public:

       M33(void){

              for(inti=0; i<3; i++)

                     for(intj=0; j<3; j++)

                            m_a[i][j]= 0;

       }

       M33(inta[][3]){          

              for(inti=0; i<3; i++)

                     for(intj=0; j<3; j++)

                            m_a[i][j]= a[i][j];

       }

       friendostream& operator<<(ostream& os,

                     constM33& m){

              for(inti=0; i<3; i++){

                     for(intj=0; j<3; j++)

                            os<< setw(4) << m.m_a[i][j];     

                     os<< endl;

              }

              returnos;

       }

       //+- *:返回值右值,左右操作数可以右值也可

       //以为左值

       constM33 operator+(const M33& m)const{

              inta[3][3]={};

              for(inti=0; i<3; i++)

                     for(intj=0; j<3; j++)

                            a[i][j]=m_a[i][j]+m.m_a[i][j];

              returna;

       }

       constM33 operator-(const M33& m)const{

              inta[3][3]={};

              for(inti=0; i<3; i++)

                     for(intj=0; j<3; j++)

                            a[i][j]=m_a[i][j]-m.m_a[i][j];

              returna;

       }

       constM33 operator*(const M33& m)const{

              inta[3][3]={};

              for(inti=0; i<3; i++)

                     for(intj=0; j<3; j++)

                            for(intk=0; k<3; k++)

                                  a[i][j]+=

                                         m_a[i][k]*m.m_a[k][j];

              returna;

       }

       //+=-= *=:返回值左值,左操作数必须是左值,右

       //操作数可以为左值也可以为右值

       M33&operator+=(const M33& m){

              return*this = *this + m;

       }

       M33&operator-=(const M33& m){

              return*this = *this - m;

       }

       M33&operator*=(const M33& m){

              return*this = *this * m;

       }

       constM33 operator-(void)const{

              returnM33() - *this;

       }

       //前++ --,操作数左值,返回值左值

       M33&operator++(void){

              for(inti=0; i<3; i++)

                     for(intj=0; j<3; j++)

                            ++m_a[i][j];

              return*this;

       }

       M33&operator--(void){

              for(inti=0; i<3; ++i)

                     for(intj=0; j<3; j++)

                            --m_a[i][j];

              return*this;

       }

       //后++ --,操作符左值,返回值右值

       constM33 operator++(int){

              M33m = *this;

              ++*this;

              returnm;

       }

       constM33 operator--(int){

              M33m = *this;

              --*this;

              returnm;

       }

       int*operator[](int i){

              returnm_a[i];

       }

       constint* operator[](int i)const{

              //复用上面的版本

              returnconst_cast<M33&>(*this) [i];

       }

 

private:

       intm_a[3][3];

};

int main(void)

{

       inta1[3][3]={1,2,3,4,5,6,7,8,9};

       inta2[3][3]={9,8,7,6,5,4,3,2,1};

       M33m1(a1);

       M33m2(a2);

       cout<< "-m2:" << endl;

       cout<< -m2 << endl;

 

       cout<< "++m2:" << endl;

       cout<< ++m2 << endl;

       cout<< m2 << endl;

       cout<< "--m2:" << endl;

       cout<< --m2 << endl;

       cout<< m2 << endl;

 

       cout<< "m2++:" << endl;

       cout<< m2++ << endl;

       cout<< m2 << endl;

       cout<< "m2--:" << endl;

       cout<< m2-- << endl;

       cout<< m2 << endl;

 

       cout<< "下标:"<< endl;

       for(inti=0;i<3;i++){

              for(intj=0;j<3;j++)

                     m2[i][j]+= 10;

       }

       cout<< m2 << endl;

       constM33& cm = m2;

       //cm[1][1]= 20;//error

 

       return0;

}

 

 


1 0
原创粉丝点击