讲解 类与对象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.用容器类对象调用对象成员所属类的公有成员函数
格式:
容器类对象成员名.对象成员所属类名::成员函数名(实参表);
四、实验内容
㈠验证及认知实验
按要求调试下列程序并回答相关问题。
程序1(exp_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.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;}
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)行首的注释去掉,编译程序时无错,而运行程序时会出现错误,其原因是 。
程序3(exp_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.分析下列程序,写出程序的输出结果,再上机运行程序验证其正确性,如果不正确,请认真分析出错原因。
|
#include<iostream.h>
class simple
{ private :
static int v1,v2,v3;
public:
simple(int x=0,int y=0)
{v1=x;v2=y;}
|
{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;
}
程序5(exp_305.cpp)
#include<iostream.h>
|
class boy;//类boy的声明;
class girl
{ private:
char *name;
|
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);//声明disp为girl类友元函数
};
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);//声明disp为boy类友元函数
};
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
|
class date
{ private:
int year,month,day;
public:
date(void)
{ year=1980;month=1;day=1;}
|
{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.完善、调试通过下列程序,并按所要求回答问题。
程序7(exp_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) ; //声明girl是boy的友元类
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; //b为boy类的一个成员
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.自已拟定一个解决实际问题的题目,综合应用“实验一”至“实验三”的知识,编写程序并调试通过