讲解 类与对象C++面向对象程序、讲解C++

- 首页 >> 其他


一、实验目的

1.理解静态数据成员、静态成员函数的作用,熟悉其应用;

2.理解常量对象、常量数据成员、常量成员函数作用,熟悉相互关系及应用;

3.熟悉友元函数、友元类的定义及应用;

4.熟悉对象成员(容器类)的应用;

5.进一步熟悉类与对象的应用及编程。

二、实验学时

课内实验:2课时        课外练习:2课时

本实验涉及的新知识

静态成员

静态成员分为静态数据成员及静态成员函数。

1.静态数据成员

静态数据成员的定义(类中定义)

格式:

static  类型  数据成员名表;

静态数据成员的作用

静态数据成员在一个类中只有一个拷贝,属于一个类(或者说属于类的第一个对象),所有对象都共享静态成员。

静态数据成员是连接各个对象的桥梁,可用来取代全局变量,主要用于各个对象都共享的公用数据,如:总数的统计、平均数等。

说明

静态数据成员可以说明为公有成员、私有成员或保护成员,但一般不说明为公有成员;

静态数据成员同其它数据成员一样,不能在类中进行初始化(不分配内存空间);

静态数据成员由于属于类(不依赖任何对象),应在程序开始运行时即生成,必须在任何函数之外进行初始化操作;

格式:

类型类名::静态数据成员=初值;

使用静态数据成员取代全局变量,使数据更为安全;

当在类中需要共享某一数据成员时通常定义为静态数据成员;

静态数据成员与静态对象是两个完全不同的概念,前者(静态数据成员)是在类中定义的,是类的所有对象共享的数据成员,而后者(静态对象)是指对象存储在静态存储区。

2.静态成员函数

静态成员函数的定义

静态成员函数是在定义类的成员函数时,在成员函数名前加上static

静态成员函数的调用方法

用类名调用

格式:

类名::静态成员函数名(实参表);

用对象调用

格式:

对象名.静态成员函数名(实参表);

说明

静态成员函数可以在类内部定义(必须加上static),也可在类外定义,即在类体内声明,在类体外定义,定义时与普通成员函数相同;

静态成员函数无this指针(this指针属于某一对象,静态成员属于一个类),只能访问静态数据成员,不能访问普通数据成员,因此静态成员函数专门用来访问静态数据成员;

当在类中定义有静态数据成员时,通常应定义静态成员函数来访问静态数据成员。

常量成员函数、常量数据成员及常量对象

C++中可以用const定义常量对象(也称为常对象)、常量成员函数(也称为常成员函数)、常量数据成员(也称为常数据成员)。

1.常量成员函数的定义

在类中定义:

返回类型 成员函数名(参数表)  const  

{    函数体      }

在类外定义

类中声明:

返回类型 成员函数名(参数表)  const

类外定义:

返回类型 类名::成员函数名(参数表)  const  

{    函数体      }

2.常量数据成员的定义

定义格式:

const  数据类型  成员名

或:

数据类型 const  成员名

3.常量对象的定义

定义格式:

类名 const 对象名表;

或:

const  类名对象名表

4.说明

常量对象只能在定义时初始化,其数据成员的值不能改变。

常量对象只能调用常量成员函数,不能调用普通成员函数;而普通对象既可调用普通成员函数,也可以调用常量成员函数。

普通成员函数可以访问本类的常量成员函数,而常量成员函数不能访问本类的普通成员函数。

常量成员函数与普通成员函数同名时,构成函数的重载,其参数类型和个数可以相同,而用const加以区分。

常量数据成员必须在构造函数中通过初始化列表进行初始化,初始化后值不能改变。

常量数据成员及成员函数隶属于某一对象(与静态数据成员的差异)。

友元

1.友元的概念

C++中提供了一种类以外的函数访问类的私有成员、保护成员的方法,即将这些函数定义为类的友元。

2.友元的种类及应用

友元函数

定义方法:在类中进行声明时,在声明的前面加上friend

说明:

友元函数不是类的成员函数,除非确因成员函数使用频繁,需要提高程序的执行效率而定义为友元函数外,一般不要定义。

友元函数可以访问对象的私有成员和保护成员,只是在类中声明时加上friend,但它不是成员函数,定义时不能在函数名前加上类名::”

友元函数无this指针,一般至少应带有一个入口参数,通过入口参数传递的对象名来引用该对象的成员。

友元函数主要用于运算符的重载。

友元成员

友元成员是指一个类的成员函数可以是另一个类的友友元函数,这样就可以通过一个类的成员函数访问另一个类的私有成员或保护成员。

说明:

一个类的成员函数要作为另一个类的友元函数时,必须先定义这个类。

由于友元函数所在的类名先于类的定义出现,应先声明。

友元类

友元类是指一个类可以作为另一个类的友元,这样友元类的所有成员函数均可以访问另一个类中的成员。

容器类

1.容器类的概念

在定义一个类的数据成员时,除可以是基本数据成员外,还可以是其它类的对象,称为对象成员。含有对象成员的类称为容器类。

2.容器类构造函数

格式

类名(形参表):成员名1(参数表1)… , 成员名n(参数表n)

说明:

容器类中至少应有一个构造函数,以通过参数表为成员对象赋初值。

创建容器类对象时,先执行对象成员所属类的构造函数,再执行容器类构造函数的函数体。

释放容器类对象时,先调用容器类的析构函数,再调用对象成员所属类的析构函数。

3.用容器类对象调用对象成员所属类的公有成员函数

格式:

容器类对象成员名.对象成员所属类名::成员函数名(实参表);

四、实验内容

验证及认知实验

按要求调试下列程序并回答相关问题。

程序1exp_301.cpp

#include<iostream.h>

class counter

{ private:

   static int count;     //count为静态数据成员

   char ch;           //普通数据成员

 public:

      counter(char c)     //构造函数

      { this->count ++;ch=c;}

      void print_counter(void)

      {cout<<ch<<":  "<<count<<endl;}

      ~counter(void)

      {count--;}

};

intcounter::count=100;   //静态数据成员赋初值

void main(void)

{ counter c1('A');

 c1.print_counter();

 cout<<endl;

 counter c2('B');

 c1.print_counter();

 c2.print_counter();

 cout<<endl;

 counter c3('C');

 c1.print_counter();

 c2.print_counter();

 c3.print_counter();

}

问题:

运行该程序的输出结果为

                         

由输出结果可知,静态成员属于                      ,在类中只有         拷贝。

程序中的“int counter::count=100;”的作用是                                ,如果将其放在main()函数中,重新编译程序,会出现                               ,其原因是                                        

程序2

//头文件“hhpoint.h”中point类的定义:

class point

{ private:

   float x,y;

 public:

      point(void)              //无参构造函数

      {x=0;y=0;}

   point(float a,float b)       //构造函数重载

      {x=a ; y=b; }

   point(const point &ob)    //拷贝构造函数

      {x=ob.x;y=ob.y;}

      void set_point(float a,float b);

      float read_x(void);

      float read_y(void);

      void move(float a,float b);

      void print(void);

};

voidpoint::set_point(float a,float b)

{x=a ; y=b; }

floatpoint::read_x(void)

{ return x;}

floatpoint::read_y(void)

{ return y;}

void point::move(float a,float b)

{ x+=a;y+=b;}

void point::print(void)

{ cout<<"x="<<x<<"  y="<<y<<endl;}

//头文件point.hpoint类的定义

class point

{ private:

   float x,y;

 public:

      point(void)              //无参构造函数

      {x=0;y=0;}

   point(float a,float b)       //构造函数重载

      {x=a ; y=b; }

   point(const point &ob)     //拷贝构造函数

      {x=ob.x;y=ob.y;}

      voidset_point(float a,float b);

      float read_x(void);

      float read_y(void);

      float read_x(void) const;

      float read_y(void) const;

      void move(float a,float b);

      void move(float a,float b) const;

};

voidpoint::set_point(float a,float b)

{x=a ; y=b; }

floatpoint::read_x(void)

{ return x;}

floatpoint::read_y(void)

{ return y;}

void point::move(float a,float b)

{ x+=a;y+=b;}

floatpoint::read_x(void) const

{ return x;}

floatpoint::read_y(void) const

{ return y;}

//voidpoint::move (float a,float b) const     //8

// { x+=a;y+=b;}                         //9

//文件“exp_302.cpp”中定义的测试程序:

#include<iostream.h>

#include"hhpoint.h"                      //(1)

//#include"point.h"                       //(2)

void main(void)

{ const point center(100,100);

 pointp(20,40);

 cout<<"Beforemoving:"<<endl;

 cout<<"p: "<<"x="<<p.read_x();

 cout<<" y="<<p.read_y()<<endl;

 cout<<"center: "<<"x="<<center.read_x();

 cout<<"  y="<<center.read_y()<<endl;

//  p.move(10,20);                      //(3)

//  cout<<"After moving:"<<endl;         //(4)

//  cout<<"p: "<<"x="<<p.read_x();      //(5)

//  cout<<"  y="<<p.read_y()<<endl;      //(6)

//  center.move(20,20);                  //(7)

}

问题:

编译程序,会出现                             ,其出错原因是                

                                     

将程序中(1)改为注释,再将(2)行首的注释去掉,再编译运行程序,程序的输出结果为:

                                       

将程序中(3)—(6)行首的注释去掉,程序的输出结果为:

                                     

将程序中的(7)行首的注释去掉,编译程序时无错,而运行程序时会出现错误,其原因是                                              

程序3exp_303.cpp

#include<iostream.h>

#include<string.h>

class girl

{ private:

      char *name;

   int age;

 public:

      girl(char *na,int n)

      { name=new char[strlen(na)+1];

       strcpy(name,na);

       age=n;

      }

      ~girl(void)    

      {delete name;}  //释放new分配的内存

      char *get_name(void)

      {return name;}

      int get_age(void)

      {return age;}

      void print_girl(void);

};

voidgirl::print_girl(void)

{cout<<"姓名:"<<name;

 cout<<"  年龄:"<<age<<endl;

}

void disp(girl&g)  

{cout<<"姓名:"<<g.name;

 cout<<"  年龄:"<<g.age<<endl;

}

void main(void)

{ girl g1("李小丫",12),g2("王永兰",15),g3("赵梦美",13);

 cout<<"姓名:"<<g1.get_name();

 cout<<"  年龄:"<<g1.get_age()<<endl;

 g2.print_girl();

 disp(g3);

}

问题:

编译程序出错的原因是                                                  

girl类中加上“friend void disp(girl &g);”重新编译、运行程序,其输出结果为:

                                     

其中,“friend void disp(girl &g);”表示函数disp( )girl类的                    

知识应用实验

1.分析下列程序,写出程序的输出结果,再上机运行程序验证其正确性,如果不正确,请认真分析出错原因。


你分析的程序输出结果是:

程序4exp_304.cpp


#include<iostream.h>

class simple

{ private :

   static int v1,v2,v3;

 public:

      simple(int x=0,int y=0)

      {v1=x;v2=y;}


程序的实际输出结果是:

      static void sum(void)


      {v3=v2+v1;}

      intget_v3(void)

      {return v3;}

};

int simple::v1=0;

int simple::v2=0;

int simple::v3=0;

void main(void)

{ simpleob1(5,10);

 ob1.sum();

 cout<<"(1):  "<<ob1.get_v3()<<endl;

 simple ob2(10,20);

 simple::sum();

 cout<<"(2):  "<<ob2.get_v3()<<endl;

}

程序5exp_305.cpp

#include<iostream.h>


你分析的程序输出结果是:

#include<string.h>


class boy;//boy的声明;

class girl

{ private:

      char *name;


程序的实际输出结果是:

   intage;


 public:

      girl(char *na,int n)

      { name=new char[strlen(na)+1];

       strcpy(name,na);

       age=n;

      }

      ~girl(void)    

      {delete name;}  //释放new分配的内存

   friend void disp(girl &g,boy &b);//声明dispgirl类友元函数

};

class boy

{ private:

      char *name;

   int age;

 public:

      boy(char *na,int n)

      { name=new char[strlen(na)+1];

       strcpy(name,na);

       age=n;

      }

      ~boy(void)    

      {delete name;}  //释放new分配的内存

   friend void disp(girl &g,boy &b);//声明dispboy类友元函数

};

void disp(girl&g,boy &b)  

//定义友元函数:不是类的成员不需要作用域运算符

{cout<<"女孩姓名:"<<g.name;

 cout<<"  年龄:"<<g.age<<endl;

 cout<<"男孩姓名:"<<b.name;

 cout<<"  年龄:"<<b.age<<endl;

}

void main(void)

{ girl g1("李小丫",12);boy b1("张海兵",15);

 disp(g1,b1);//调用友元函数:与普通函数调用相同

}

程序6


你分析的程序输出结果是:

//头文件“hdate.h”的内容://定义“date”类


class date      

{ private:

   int year,month,day;

 public:

      date(void)

      { year=1980;month=1;day=1;}


程序的实际输出结果是:

      date(int y,int m,int d)


      {year=y;month=m;day=d;}

      int get_year(void) {return year;}

      int get_month(void) {return month;}

      int get_day(void) {return day;}

};

//头文件“hperson.h”的内容:定义“person”类

#include<string.h>

#include"hdate.h"

class person

{ private:

   char *name;

      char sex[2];

      date birthday;

 public:

   person(char *na,char *s,int y,int m,intd):birthday(y,m,d)

      { name=new char[strlen(na)+1];

       strcpy(name,na);

       strcpy(sex,s);

      }

      char *get_name(void){return name;}

      char *get_sex(void){return sex;}

      int get_year(void){returnbirthday.get_year();}

      int get_month(void){return  birthday.get_month();}

      int get_day(void){return  birthday.get_day();}

      ~ person(void){delete []name;}

      void print(void);

};

voidperson::print(void)

{cout<<"姓名:"<<name<<endl;

 cout<<"性别:"<<sex<<endl;

 cout<<"出生日期:"<<birthday.get_year()<<"";

 cout<<birthday.get_month()<<"";

 cout<<birthday.get_day()<<""<<endl;

}

//测试程序“exp_306.cpp

#include<iostream.h>

#include"hperson.h"

void main(void)

{ personps1("张小三","",1985,12,15);

 person ps2("李小丫","",1986,3,9);

 ps1.print();

 cout<<endl;

 ps2.print();

}

2.完善、调试通过下列程序,并按所要求回答问题。

程序7exp_307.cpp

#include<iostream.h>

#include<string.h>

class boy;//boy的声明;

class girl

{ private:

      char *name;

   int age;

 public:

      girl(char *na,int n)

      { name=new char[strlen(na)+1];

       strcpy(name,na);

       age=n;

      }

      ~girl(void)    

      {delete name;}  //释放new分配的内存

   void disp(   (1)       );

};

class boy

{ private:

      char *name;

   int age;

      (2)   ;     //声明girlboy的友元类

 public:

      boy(char *na,int n)

      { name=new char[strlen(na)+1];

       strcpy(name,na);

       age=n;

      }

      ~boy(void)    

      {delete name;}  //释放new分配的内存

};

void girl::disp(   (1)      )  

{cout<<"女孩姓名:"<<name;    

 cout<<"  年龄:"<<age<<endl;

 cout<<"男孩姓名:"<<b.name;     //bboy类的一个成员

 cout<<"  年龄:"<<b.age<<endl;

}

void main(void)

{ girl g1("李小丫",12);boy b1("张海兵",15);

 g1.disp(b1);

}

程序设计实验

编写程序,定义一个平面点“Point”类及计算两点之间距离“Distance”类,将“Distance”类定义为“Point”类的友元类;并在main()中计算任意两点的距离(保存在exp_308.cpp中)。

四、实验收获与创新

1.通过“实验一”至“实验三”,谈谈你对面向对象程序设计“数据封装与隐藏”的认识。

2.自已拟定一个解决实际问题的题目,综合应用“实验一”至“实验三”的知识,编写程序并调试通过