数据结构预备知识(二)

本文详细介绍了C++中类的定义与使用,包括构造函数、成员函数、对象指针等核心概念,并提供了丰富的示例代码,帮助读者深入理解面向对象编程的基础。
二.        类和对象

1.类的定义

class      类名称
           {  private:     数据成员;
                                  成员函数;
               protected: 数据成员;
                                  成员函数;
               public:       数据成员;
                                成员函数;
          };       //类定义结束 必须有分号“ ;”

class  是保留字, 作用与struct 相同  定义一个结构也叫类。  
private(私有), 缺省 
protected(保护) , 
 public(公有)
都是访问限制

例 计数器类  存储于文件“count.h”中

class  counter 
  {  private:      //私有成员
         unsigned  int  value;  //数据成员
     public:     //公有成员
         counter( ) { value=0;} //无参构造函数
         counter(int x){ if(x>0)value=x; 
                            else value=0;}//有参构造函数
         void increment( ){if(value<65535)value++;} 
         void decrement( ){if(value>0)value--;}
         unsigned access_value( ){return value;} 
   }; 

2. 对象的定义  object

     counter c1, c2;    //语句1
     counter c3(5);     //语句2


语句1定义counter 类的对象c1, c2,即实际变量
(实例)。
对象定义时必须为数据成员赋初值即初始化。初始化由类中的构造函数自动完成。语句1 自动调用 counter 类中无参构造函数,使
c1.value=c2.value=0。
   
语句2定义对象c3, 自动调用有参构造函数使c3.value=5.


注意:不能使用c1.value为它赋值;  因为 value 在counter类中是私有成员不可见,只能用成员函数来调用。 
对象不能直接调用私有成员,只能通过公有成员函数来调用私有成员
对象调用成员函数,叫发一个消息
为c1发消息:
  c1.increment( );   //计数器自动加1
  c1.decrement( ); // 计数器自动减1

例 计数器测试程序
#include  “iostream.h”
 #include  “count.h”
 void main( )
 { counter c1,c2;
    for( int  i=1; i<=8;i++)
     {c1.increment( );
       cout<<“ \nc1=” <<c1.access_value( );
       c2.increment( );   }
    cout<<“      c2=” <<c2.access_value( );
     for( i=1; i<=5;i++)
      {c2.decrement( );
        cout<<“ \nc2=” <<c2.access_value( );
        c1.decrement( );  }
    cout<<“       c1=” <<c1.access_value( );
  }

测试结果    
c1=1
c1=2
c1=3
c1=4
c1=5
c1=6
c1=7
c1=8          c2=8
c2=7
c2=6
c2=5
c2=4
c2=3         c1=3

圆的类

class Circle
{   float  radius;
   public:
     Circle(float r=0):radius(r){}//构造函数
     float GetRadius( );
     float CircleCircum( );
     float CircleArea( );
  };

成员函数类外定义

Circle:: Circle(float r) //构造函数
  {   radius = r;  }
float Circle:: GetRadius( )
  {  return  radius;}
float Circle:: CircleCircum( )
  {  return  2*3.14.6*radius;  }
float Circle:: CircleArea( )
  {  return   3.1416*radius*radius; }

圆类的测试

#include  “iostream.h”
 #include  “circle.h”
 void main( )
 { Circle a(3), b(2);
    cout<<“Circum of Circle a = ”
           <<a.CircleCircum( )<<endl;
    cout<<“Area of Circle b = ”
           <<b.CircleArea( )<<endl;
}

长方形类

class Rectangle
{    float x, y;
    public:
      Rectangle(float a=0, float b=0): x(a),y(b)
      {  }
     float RecCircum( ){return 2*(x+y);}
     float RecArea( ){return x*y;}
};

3. 对象指针和对象数组

  a. 对象指针
 如同定义一个对象一样,用类名可以申明一个对象指针。


   例   counter *p,*q;


申明counter 类的指针,指针没有初始化,
调用指针必须先分配内存,或指向一个变量的地址,否则出严重错误,甚至死机。

(1) p=new counter(3);
    分配一个整形数据内存,这时系统自动调用有参
    构造函数初始化*p的value=3;


(2)q=new counter[3];
   分配三个连续整形数据内存,这时系统自动调用无参构造函数初始化
   q,q+1,  q+2的value都是0。


  如果类中没有无参构造函数,语句(2)出错。

 确定地址后的对象指针可以调用类中公有数
  据及公有函数。
         p→increment( );  
        (q+1) →decrement( );
         (*p).decrement( );    
   
    (*p).decrement( )中的括号不能省略,因为
    运算符 .  的优先级高于*;    


    对象指针用毕,要予以撤销,释放内存,
    delete  p;   delete[ ] q;


 撤销后的指针可以再用,只要重新分配内存或指向一个内存。

b. 对象数组
       如果类中有无参构造函数,可以定义对象数组
(3)      counter  c[3]; 


这时系统自动调用无参构造函数初始化c[0],c[1],c[2]的value都是0。
如果类中没有无参构造函数,语句(3)出错。

4. 类的数据成员

a. 一个类中的数据成员不可以初始化,
例  class A
      { int value=0;\\出错
        .......};
b. 另一个类的对象可以做本类的数据成员,但要先定义后作成员。
只先申明不行。本类对象不可以做自己的数据成员。
c. 指向本类或另一类对象的指针,或引用可以作本类的数据成员。
只要先申明就可以。

d. 公有成员和私有成员的先后次序可以交换。可以把私有成员写在类的前部,也可以写在后部。
e. 本类对象可以调用本类公有数据或公有函数,不能调用私有数据和私有成员。

例 class A;
   class B
    {   A *p;    //合法
        A& q;    //合法
        B * r;    //合法
        A  a;    //出错
        B  b;     //出错
   };

长方形和圆的类

class RecCircle
{    Rectangle Rec;
      Circle Cir;
   public:
     RecCircle(float a, float b, float c):
            Rec(a,b), Cir(c){ }
     float Circum( ){return            
        Rec.RecCircum( )+Cir.CircleCircum( );}
     float Area( ){ return
         Rec.RecArea( )+Cir.CircleArea( );
};

5. 类的 成员函数

成员函数也叫类所具有的方法或操作。
函数头叫方法的界面,也叫消息模式。
函数可以重载(要求参数不同)不必用overload。
可以类内申明类外定义,类内定义时不用inline即内联。
成员函数可以调用本类数据成员,无论公有或私有。
对象调用公有成员函数叫做发一个消息。

构造函数可以重载,带缺省参数时,要特别注意避免二义性。  
构造函数一般都是公有函数。只有私有构造函数的类不能定义对象。
只有本类对象或本类成员函数才能调用成员函数。
 6. This 指针

成员函数必须由对象调用,调用成员函数的对象可以看作一个隐含的参数,这是一个指针参数,用this表示。this 指针指向调用成员函数的对象。
例   Circle::CircleArea( )
      {return 3.1416*radius*radius;}   
      //其中   radius 实际意义是this→radius .


Circle a(3.4);
cout <<a.CircleArea( );//this指针指向a

counter::increament( )
{if(value<65535)value++;}
//隐含参数this指针, this->value 


counter c;
c.increament( );
//实际参数是c, this 指向c

7. 构造函数

       与类名同名的成员函数叫构造函数,构造函数没有返回类型。构造函数的作用是自动为对象初始化。对象不能调用构造函数。
       如果一个类中没有构造函数,系统会自动生成一个无参构造函数。如果一个类中有有参构造函数,系统就不再自动生成无参构造函数,这时,用类定义对象数组或对象指针都可能出错。

一个类中如果没有构造函数,系统会自动生成 一个无参构造函数,使所有的数据成员都置0。   一个类中如果有有参构造函数,系统就不再生 成无参构造函数。
例如  RecCirle类中,就没有无参构造函数。 这时要小心,下面一个语句会出错          RecCircle  d;   //出错 无法初始化          RecCircle s[3]; //出错 无法初始化
正确的定义形式是           RecCircle  d(2.0, 3.5, 4);
8. 拷贝构造函数

构造函数的参数不能是本类对象,但可以是本类对象的引用,
这样的构造函数叫拷贝构造函数。

class Circle

{   float  radius;
   public:
     Circle(float r=0):radius(r){}//构造函数
     Circle(Circle & c){radius=c.radius;}
     // 拷贝构造函数
     float GetRadius( );
     float CircleCircum( );
     float CircleArea( );
  };

拷贝构造函数的作用:
1) 用已有对象定义新的对象。
         Circle  a(2);
          Circle  b(a);
     第二个语句就是利用拷贝构造函数定义赋数对象b, b的半径等于a的半径。 
2) 本类对象作函数的参数时,要用拷贝构造函数传值。
3) 一个函数的返回值是本类对象时,要用拷贝构造函数赋值。
Circle Fun(Circle t)
{ return Circl(2*t.radius);}
如果类中没有拷贝构造函数系统会自动生成一个。
如果类中有指针成员,就必须专门定义拷贝构造函数,否则可能出错。
例  class A
           {    int *p;
              pubic:
                A( ){p= new  int(0);}
                  A(A&s){p=new int(*s.p);
           };
9.  析构函数

   以~开头与类名同名的成员函数称为析构函数。析构函数无参无返回值。
    例   class  A
          {....
            ~A( );
            ....};
析构函数的作用: 当本类的一个对象用完后,系统自动调用析构函数,撤销内存。


这种情况常在一个函数中发生,一个对象在函数中作局部变元,函数用毕后,局部变元失效,析构函数就会自动起作用。


类中没有析构函数时系统会自动生成一个析构函数。


当类中含有指针对象时,应当定义一个析构函数,以免指针指向的内存挂起失。
class  A
{    int *p;
     public:
      A( ){p=new int;}
            ....
     ~A( ){delete p;}
            ....};


注意 类外对象指针用 new 分配的内存,不会调用析构函数,而要用delete释放。
例 坐标点point类

class Point 
{ public:
       Point(int,int);   //构造函数
       Point(Point &);//拷贝构造函数
       //~Point( );            析构函数
       int get_x( );       //取横坐标
       int get_y( );      //取纵坐标
       Point operator+(Point&); //重载+
       Point operator *(int);    //重载*
       Point operator-( );     //一元函数-重载
       Point& operator=(const Point&);  //赋值函数
      
    private:          //私有数据
       int x, y;


     friend istream& operator>>(istream&, Point&);
     //友元   输入函数重载>>
     friend ostream& operator<<(ostream&,Point&);
     //友元   输出函数重载<< 
};

Point::Point(int a, int b)
{x=a; y=b;}

Point::Point(Point& p)
{x=p.get_x( ); y=p.get_y( );}

int Point::get_x( )
{return x;}

int Point::get_y( )
{return y;}

Point Point::operator+(Point &p)
{x=x+p.x; y=y+p.y; return*this;}

Point Point::operator *(int n)
{x=n*x; y=n*y;  return*this;}

Point Point::operator-( )
{x=-x; y=-y; return *this;}

Point&  Point::operator=(const Point& p)
{ x=p.x; y=p.y; return *this;} 
istream& operator>>(istream& istr, Point& p)
{  istr>>p.x>>p.y; return istr; }
ostream& operator<<(ostream& ostr, Point& p)
{  ostr<<“(”<<p.x<<“,”<<p.y<<“)”<<endl;
    return ostr; }
11. 运算符(操作符)重载

除了少数几个操作符,如 “,” ,“::” ,“?:” ,“{ }”之外,其余都可以重载。
二元运算在成员函数看来,只有一个参数,另一个是this指针。

例 Point  Point::operator +(Point & c);
二元运算+在复数类中重载,变成只有一个参数。

 Point   a1(1,2) ,  a2(2,-1);
  a1=a1+a2;
  表达式a1=a1+a2中对象a1调用运算+,实
际参数为a2,返回值还是 Point类型,
还可以再调用运算符+,因此表达式
a1+a2+a1有意义。

12. 赋值函数重载

   在class Point 中重载赋值函数
  
 class Point
       { ....
       Point&  operator=(const Point& c)
                   { x=c.x; y=c.y; return *this;} 
          ......


         };

   赋值函数的作用是把一个对象的所有内容,赋予另一个对象.
    c1=c2;   c1=c1+c2;


类中没有赋值函数时系统会自动生成一个赋值函数。当类中含有指针对象时,应当定义一个赋值函数,以保证值把内容赋值,而不是把地址赋值造成析构函数调用时出错。

 例  class  A
         {  int *p;
           public:
             .....
             A& operator=(A& a)
              { if (this=&a) return *this;
                else *p=*a.p;return *this;}
              .....
          };

13. 一元运算重载

    一元运算作成员函数重载时变成零元函数。


     Point  Point :: operator -( )
      {x=-x;y=-y;return  return *this;}


    调用写成   -c1 或   c1=-c2;

10. 友元

友元有权访问类内所有成员,不论公有,保护,还是私有成员。
友元没有this指针,必要时可以用类对象的引用作参数。
友元可以是一个类,这时友元类中所有成员函数都是友元。
友元不传递,不对称,不继承。
友元没有this指针,比成员函数多一个参数。

istream& operator>>(istream& istr, Point& p)
{  istr>>p.x>>p.y; return istr; }

ostream& operator<<(ostream& ostr, Point& p)
{  ostr<<“(”<<p.x<<“,”<<p.y<<“)”<<endl;
    return ostr; }

友元不是类的成员,不用类名域  Point::operator

函数在类内申明类外定义 例 日期类保存于“date.h”中

class  date          
   {    int  month, day, year; //私有数据
       public:
         date(int, int, int); //有参构造函数
         void  next( );   
         void  print( );
  }today;  

inline date::date(int a, int b, int c)
       { month=a;  day=b;  year=c;}

void  date:: print( )
        { cout<<month<<“   /”<<day;
           cout<<“  /”<<year<<endl;}

void  date::next( )
{ switch  month
   case 1: case3: case 5: case 7: case 8: case 10:
    { if(day<31)day++;
     else {month++;day=1;}}break;   
   case 4: case 6: case 9: case 11:
    { if(day<30)day++;
     else {month++;day=1;}}break;  
   case 12:
    { if(day<31)day++;
         else {year++;month=1;day=1;}}break;  
   case 2:

if((year%4==0)&&year%400!=0)
      | |(year%400= =0))
          { if(day<29)day++;
              else {month++;day=1;}}  
  else{ if(day<28)day++;
              else {month++;day=1;}}
    }



例  date 类测试程序
 #include “  iostream.h”
 #include “  date.h”
 
void main( ) 
 { date today(2,13,2001);//定义对象
    date   myBirthday(6,24,1983);//定义对象
    today.next( );//对象调用操作
    today.print( );
    myBirthday.print( );
 }

测试结果


2/14/2001
6/24/1983

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值